Compare commits
91 Commits
last-outsi
...
wip-front-
Author | SHA1 | Date | |
---|---|---|---|
![]() |
053570e55d | ||
![]() |
ab98261889 | ||
![]() |
97bf76f9ba | ||
![]() |
f876961e1c | ||
1bf90a6f6e | |||
aa40e8903b | |||
![]() |
0f5c409c04 | ||
![]() |
bd2c8893dd | ||
![]() |
73730a81c8 | ||
![]() |
a9a267df2a | ||
![]() |
09ae6712bb | ||
![]() |
78702cc5e0 | ||
![]() |
515ef5e1b5 | ||
![]() |
19f9734349 | ||
![]() |
bb3adc37d3 | ||
![]() |
0e11c2b923 | ||
![]() |
929edb9f90 | ||
![]() |
131bb26e9e | ||
![]() |
9023e32c47 | ||
![]() |
c34d2c3a41 | ||
![]() |
27ea3a6c1b | ||
![]() |
b91aeadb45 | ||
![]() |
a4bbff1ad0 | ||
![]() |
ecd09a3f02 | ||
![]() |
dbdd32bf0d | ||
![]() |
94b6ee3020 | ||
![]() |
1f9b0eda42 | ||
![]() |
97c74f3267 | ||
![]() |
1342ed2601 | ||
![]() |
3dcf8ba93a | ||
![]() |
5b14d78037 | ||
![]() |
c8f6ba207b | ||
663cf7bf2d | |||
4e8530478a | |||
b2d10b5ca7 | |||
fad1aa75e9 | |||
d9cf2d8631 | |||
34cb45d5f1 | |||
3c74e79e4a | |||
fb2f245f1e | |||
8c6fa1e423 | |||
b66b6cf445 | |||
b153cae70e | |||
368e3f6d40 | |||
e9ec850d90 | |||
280d26801e | |||
6c285c078f | |||
debfc4e356 | |||
541663ce0c | |||
1fb044e7c1 | |||
4769e2e904 | |||
cf99383b9c | |||
8613ac7244 | |||
8c48a61114 | |||
0259c5e0ec | |||
a726fd1fbe | |||
df71738623 | |||
6a698daaa0 | |||
7f538bdaee | |||
5f07c7ce17 | |||
5a42e2dcb8 | |||
d5a54b7cf1 | |||
7cb4b37ae2 | |||
1fca473257 | |||
5a6035a494 | |||
98698be7eb | |||
d4f072480c | |||
2d036ee657 | |||
1bb762db6b | |||
11743c54e2 | |||
29d1d02bfd | |||
f7e5db2174 | |||
2141aed06c | |||
6b56df9e9c | |||
5a4519659a | |||
c3ddc831aa | |||
1a63b51c48 | |||
484ac34c50 | |||
908360eb1c | |||
3bf1c3ea1b | |||
fc58fbef5b | |||
9e961580d3 | |||
87cf5a9844 | |||
5a3a7a3883 | |||
3be926b9b3 | |||
ff5af22771 | |||
6f73222dcd | |||
1617a119db | |||
bef402a6b0 | |||
94ef616593 | |||
ffc4f271e8 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -18,3 +18,7 @@ node_modules/
|
||||
/google_app*.json
|
||||
/docker/2_buildpy/python/
|
||||
/docker/4_run/wheelhouse/
|
||||
/docker/4_run/deploy/
|
||||
/celerybeat-schedule.bak
|
||||
/celerybeat-schedule.dat
|
||||
/celerybeat-schedule.dir
|
||||
|
140
README.md
140
README.md
@@ -3,45 +3,95 @@
|
||||
Welcome to the [Blender Cloud](https://cloud.blender.org/) code repo!
|
||||
Blender Cloud runs on the [Pillar](https://pillarframework.org/) framework.
|
||||
|
||||
## Quick setup
|
||||
Set up a node with these commands.
|
||||
## Development setup
|
||||
Jumpstart Blender Cloud development with this simple guide.
|
||||
|
||||
### System setup
|
||||
Blender Cloud relies on a number of services in order to run. Check out the [Pillar system setup](
|
||||
https://pillarframework.org/development/system_setup/#step-by-step-setup) to set this up.
|
||||
|
||||
Add `cloud.local` to the `/etc/hosts` file on localhost. This is a development convention.
|
||||
|
||||
### Check out the code
|
||||
Go to the local development directory and check out the following repositories, next to each other.
|
||||
|
||||
```
|
||||
#!/usr/bin/env bash
|
||||
|
||||
sudo mkdir -p /data/{git,storage,config,certs}
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install python3-pip
|
||||
pip3 install docker-compose
|
||||
|
||||
cd /data/git
|
||||
cd /home/guest/Developer
|
||||
git clone git://git.blender.org/pillar-python-sdk.git
|
||||
git clone git://git.blender.org/pillar.git -b production
|
||||
git clone git://git.blender.org/attract.git -b production
|
||||
git clone git://git.blender.org/flamenco.git -b production
|
||||
git clone git://git.blender.org/blender-cloud.git -b production
|
||||
git clone https://github.com/armadillica/grafista.git -b production
|
||||
|
||||
echo '0 8 * * * root docker exec -d grafista bash manage.sh collect' > /etc/cron.d/grafista
|
||||
|
||||
git clone git://git.blender.org/pillar.git
|
||||
git clone git://git.blender.org/attract.git
|
||||
git clone git://git.blender.org/flamenco.git
|
||||
git clone git://git.blender.org/pillar-svnman.git
|
||||
git clone git://git.blender.org/blender-cloud.git
|
||||
```
|
||||
|
||||
After these commands, run `deploy.sh` to build the static files and deploy
|
||||
those too (see below).
|
||||
### Initial setup and configuration
|
||||
|
||||
Create a virtualenv for the project and install the requirements:
|
||||
|
||||
```
|
||||
cd blender-cloud
|
||||
mkvirtualenv blender-cloud -p python3.6
|
||||
pip install -r requirements-dev.txt
|
||||
```
|
||||
|
||||
Build assets and templates for all Blender Cloud dependencies using Gulp.
|
||||
|
||||
```
|
||||
./gulp all
|
||||
```
|
||||
|
||||
Make a copy of the config_local example, which will be further edited as the application is
|
||||
configured.
|
||||
|
||||
```
|
||||
cp config_local.example.py config_local.py
|
||||
```
|
||||
|
||||
Setup the database with the initial collections and the admin user.
|
||||
|
||||
```
|
||||
./manage.py setup setup_db your_email
|
||||
```
|
||||
|
||||
The command will return the following message:
|
||||
|
||||
```
|
||||
Created project <project_id> for user <user_id>
|
||||
```
|
||||
|
||||
Copy the value of `<project_id>` and assign it as value for `MAIN_PROJECT_ID`.
|
||||
|
||||
Run the application:
|
||||
|
||||
```
|
||||
./manage.py runserver
|
||||
```
|
||||
|
||||
|
||||
## Deploying to production server
|
||||
## Development
|
||||
|
||||
First of all, add those aliases to the `[alias]` section of your `~/.gitconfig`
|
||||
When ready to commit, change the remotes to work over SSH. For example:
|
||||
|
||||
`git remote set-url origin git@git.blender.org:blender-cloud.git`
|
||||
|
||||
For more information, check out [this guide](https://wiki.blender.org/wiki/Tools/Git#Commit_Access).
|
||||
|
||||
|
||||
## Preparing the production branch for deployment
|
||||
|
||||
All revisions to deploy to production should be on the `production` branches of all the relevant
|
||||
repositories.
|
||||
|
||||
Make sure you have these aliases in the `[alias]` section of your `~/.gitconfig`:
|
||||
|
||||
```
|
||||
prod = "!git checkout production && git fetch origin production && gitk --all"
|
||||
ff = "merge --ff-only"
|
||||
pp = "!git push && if [ -e deploy.sh ]; then ./deploy.sh; fi && git checkout master"
|
||||
```
|
||||
|
||||
The following commands should be executed for each subproject; specifically for
|
||||
Pillar and Attract:
|
||||
The following commands should be executed for each (sub)project; specifically for
|
||||
the current repository, Pillar, Attract, Flamenco, and Pillar-SVNMan:
|
||||
|
||||
```
|
||||
cd $projectdir
|
||||
@@ -64,35 +114,19 @@ git ff master
|
||||
# Run tests again
|
||||
py.test
|
||||
|
||||
# Push the production branch and run dummy deploy script.
|
||||
git pp # pp = "Push to Production"
|
||||
|
||||
# The above alias waits for [ENTER] until all deploys are done.
|
||||
# Let it wait, perform the other commands in another terminal.
|
||||
# Push the production branch.
|
||||
git push
|
||||
```
|
||||
|
||||
Now follow the above receipe on the Blender Cloud project as well.
|
||||
Contrary to the subprojects, `git pp` will actually perform the deploy
|
||||
for real.
|
||||
## Deploying to production server
|
||||
|
||||
Now you can press `[ENTER]` in the Pillar, Attract, and Flamenco terminals
|
||||
that were still waiting for it.
|
||||
```
|
||||
workon blender-cloud # activate your virtualenv
|
||||
cd $projectdir/deploy
|
||||
./2docker.sh
|
||||
./build-all.sh # or ./build-quick.sh
|
||||
./2server.sh servername
|
||||
```
|
||||
|
||||
After everything is done, your (sub)projects should all be back on
|
||||
the master branch.
|
||||
|
||||
|
||||
## Updating dependencies via Docker images
|
||||
|
||||
To update dependencies that need compiling, you need the `2_build` docker
|
||||
container. To rebuild the lot, run `docker/build.sh`.
|
||||
|
||||
Follow these steps to deploy the new container on production:
|
||||
|
||||
1. run `docker/build.sh`
|
||||
2. `docker push armadillica/blender_cloud`
|
||||
|
||||
On the production machine:
|
||||
|
||||
1. `docker pull armadillica/blender_cloud`
|
||||
2. `docker-compose up -d` (from the `/data/git/blender-cloud/docker` directory)
|
||||
To deploy another branch than `production`, do `export DEPLOY_BRANCH=otherbranch` before starting
|
||||
the above commands.
|
||||
|
@@ -17,6 +17,8 @@ from pillar.web.utils import attach_project_pictures
|
||||
from pillar.web.settings import blueprint as blueprint_settings
|
||||
from pillar.web.nodes.routes import url_for_node
|
||||
from pillar.web.nodes.custom.comments import render_comments_for_node
|
||||
from pillar.web.projects.routes import render_project
|
||||
from pillar.web.projects.routes import find_project_or_404
|
||||
|
||||
|
||||
blueprint = Blueprint('cloud', __name__)
|
||||
@@ -62,15 +64,6 @@ def _homepage_context() -> dict:
|
||||
post.picture = get_file(post.picture, api=api)
|
||||
post.url = url_for_node(node=post)
|
||||
|
||||
# Render attachments
|
||||
try:
|
||||
post_contents = post['properties']['content']
|
||||
except KeyError:
|
||||
log.warning('Blog post %s has no content', post._id)
|
||||
else:
|
||||
post['properties']['content'] = pillar.web.nodes.attachments.render_attachments(
|
||||
post, post_contents)
|
||||
|
||||
# Get latest assets added to any project
|
||||
latest_assets = Node.latest('assets', api=api)
|
||||
|
||||
@@ -443,6 +436,32 @@ def comments_for_node(node_id):
|
||||
return render_comments_for_node(node_id, can_post_comments=can_post_comments)
|
||||
|
||||
|
||||
@blueprint.route('/p/hero')
|
||||
def project_hero():
|
||||
api = system_util.pillar_api()
|
||||
project = find_project_or_404('hero',
|
||||
embedded={'header_node': 1},
|
||||
api=api)
|
||||
# Load the header video file, if there is any.
|
||||
header_video_file = None
|
||||
header_video_node = None
|
||||
if project.header_node and project.header_node.node_type == 'asset' and \
|
||||
project.header_node.properties.content_type == 'video':
|
||||
header_video_node = project.header_node
|
||||
header_video_file = get_file(project.header_node.properties.file)
|
||||
header_video_node.picture = get_file(header_video_node.picture)
|
||||
|
||||
pages = Node.all({
|
||||
'where': {'project': project._id, 'node_type': 'page'},
|
||||
'projection': {'name': 1}}, api=api)
|
||||
|
||||
return render_project(project, api,
|
||||
extra_context={'header_video_file': header_video_file,
|
||||
'header_video_node': header_video_node,
|
||||
'pages': pages._items,},
|
||||
template_name='projects/landing.html')
|
||||
|
||||
|
||||
def setup_app(app):
|
||||
global _homepage_context
|
||||
cached = app.cache.cached(timeout=300)
|
||||
|
55
cloud/static/assets/js/layout.min.js
vendored
Normal file
55
cloud/static/assets/js/layout.min.js
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
/* Variables
|
||||
================================================================== */
|
||||
var searchToggleStatus = false
|
||||
|
||||
/* Selectors
|
||||
================================================================== */
|
||||
var searchButton = document.querySelector('#searchButton'),
|
||||
searchCloseButton = document.querySelector('#searchCloseButton'),
|
||||
searchNav = document.querySelector('#searchNav'),
|
||||
searchNavInput = document.querySelector('#searchNav input'),
|
||||
navbarNav = document.querySelector('#navbarNav'),
|
||||
profileMenu = document.querySelector('#navbarNav .navbar-nav').lastElementChild
|
||||
|
||||
/* Interactions
|
||||
================================================================== */
|
||||
searchButton.addEventListener('click', showSearch)
|
||||
searchCloseButton.addEventListener('click', closeSearch)
|
||||
|
||||
|
||||
/* Functions
|
||||
================================================================== */
|
||||
function showSearch() {
|
||||
searchToggleStatus = true
|
||||
searchNav.classList.remove('hidden')
|
||||
searchNavInput.focus()
|
||||
navbarNav.classList.add('hidden')
|
||||
profileMenu.classList.add('visible')
|
||||
// $('#search-overlay').addClass('visible')
|
||||
// if (searchToggleStatus == true) {
|
||||
// // $(document.body).click(function() {
|
||||
// // console.log('detect click outside');
|
||||
// // searchToggleStatus = false
|
||||
// // })
|
||||
// console.log(searchToggleStatus);
|
||||
// console.log('detect click outside');
|
||||
// searchToggleStatus = false
|
||||
// console.log(searchToggleStatus);
|
||||
// } else {
|
||||
// console.log(searchToggleStatus);
|
||||
// console.log('not detecting clicks');
|
||||
|
||||
// }
|
||||
// $(document.body).click(function () {
|
||||
// console.log('detected click outside');
|
||||
// searchToggleStatus == false
|
||||
// }) else {
|
||||
// }
|
||||
}
|
||||
|
||||
function closeSearch() {
|
||||
searchNav.classList.add('hidden')
|
||||
navbarNav.classList.remove('hidden')
|
||||
profileMenu.classList.remove('visible')
|
||||
// $('#search-overlay').removeClass('active')
|
||||
}
|
32
config_local.example.py
Normal file
32
config_local.example.py
Normal file
@@ -0,0 +1,32 @@
|
||||
import os
|
||||
|
||||
DEBUG = True
|
||||
|
||||
BLENDER_ID_ENDPOINT = 'http://id.local:8000'
|
||||
|
||||
SERVER_NAME = 'cloud.local:5001'
|
||||
SCHEME = 'http'
|
||||
PILLAR_SERVER_ENDPOINT = f'{SCHEME}://{SERVER_NAME}/api/'
|
||||
|
||||
os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = 'true'
|
||||
os.environ['PILLAR_MONGO_DBNAME'] = 'cloud'
|
||||
os.environ['PILLAR_MONGO_PORT'] = '27017'
|
||||
os.environ['PILLAR_MONGO_HOST'] = 'mongo'
|
||||
|
||||
os.environ['PILLAR_SERVER_ENDPOINT'] = PILLAR_SERVER_ENDPOINT
|
||||
|
||||
SECRET_KEY = '##DEFINE##'
|
||||
|
||||
OAUTH_CREDENTIALS = {
|
||||
'blender-id': {
|
||||
'id': 'CLOUD-OF-SNOWFLAKES-42',
|
||||
'secret': '##DEFINE##',
|
||||
}
|
||||
}
|
||||
|
||||
MAIN_PROJECT_ID = '##DEFINE##'
|
||||
URLER_SERVICE_AUTH_TOKEN = '##DEFINE##'
|
||||
|
||||
ZENCODER_API_KEY = '##DEFINE##'
|
||||
ZENCODER_NOTIFICATIONS_SECRET = '##DEFINE##'
|
||||
ZENCODER_NOTIFICATIONS_URL = 'http://zencoderfetcher/'
|
164
deploy.sh
164
deploy.sh
@@ -1,164 +0,0 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
case $1 in
|
||||
cloud*)
|
||||
DEPLOYHOST="$1"
|
||||
;;
|
||||
*)
|
||||
echo "Use $0 cloud{nr}|cloud.blender.org" >&2
|
||||
exit 1
|
||||
esac
|
||||
|
||||
echo -n "Deploying to ${DEPLOYHOST}... "
|
||||
|
||||
if ! ping ${DEPLOYHOST} -q -c 1 -W 2 >/dev/null; then
|
||||
echo "host ${DEPLOYHOST} cannot be pinged, refusing to deploy." >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
echo "press [ENTER] to continue, Ctrl+C to abort."
|
||||
read dummy
|
||||
|
||||
|
||||
# Deploys the current production branch to the production machine.
|
||||
PROJECT_NAME="blender-cloud"
|
||||
DOCKER_NAME="blender_cloud"
|
||||
CELERY_WORKER_DOCKER_NAME="celery_worker"
|
||||
CELERY_BEAT_DOCKER_NAME="celery_beat"
|
||||
REMOTE_ROOT="/data/git/${PROJECT_NAME}"
|
||||
|
||||
SSH="ssh -o ClearAllForwardings=yes -o PermitLocalCommand=no ${DEPLOYHOST}"
|
||||
|
||||
# macOS does not support readlink -f, so we use greadlink instead
|
||||
if [[ `uname` == 'Darwin' ]]; then
|
||||
command -v greadlink 2>/dev/null 2>&1 || { echo >&2 "Install greadlink using brew."; exit 1; }
|
||||
readlink='greadlink'
|
||||
else
|
||||
readlink='readlink'
|
||||
fi
|
||||
|
||||
ROOT="$(dirname "$($readlink -f "$0")")"
|
||||
cd ${ROOT}
|
||||
|
||||
# Check that we're on production branch.
|
||||
if [ $(git rev-parse --abbrev-ref HEAD) != "production" ]; then
|
||||
echo "You are NOT on the production branch, refusing to deploy." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check that production branch has been pushed.
|
||||
if [ -n "$(git log origin/production..production --oneline)" ]; then
|
||||
echo "WARNING: not all changes to the production branch have been pushed."
|
||||
echo "Press [ENTER] to continue deploying current origin/production, CTRL+C to abort."
|
||||
read dummy
|
||||
fi
|
||||
|
||||
function find_module()
|
||||
{
|
||||
MODULE_NAME=$1
|
||||
MODULE_DIR=$(python <<EOT
|
||||
from __future__ import print_function
|
||||
import os.path
|
||||
try:
|
||||
import ${MODULE_NAME}
|
||||
except ImportError:
|
||||
raise SystemExit('${MODULE_NAME} not found on Python path. Are you in the correct venv?')
|
||||
|
||||
print(os.path.dirname(os.path.dirname(${MODULE_NAME}.__file__)))
|
||||
EOT
|
||||
)
|
||||
|
||||
if [ $(git -C $MODULE_DIR rev-parse --abbrev-ref HEAD) != "production" ]; then
|
||||
echo "${MODULE_NAME}: ($MODULE_DIR) NOT on the production branch, refusing to deploy." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo $MODULE_DIR
|
||||
}
|
||||
|
||||
# Find our modules
|
||||
PILLAR_DIR=$(find_module pillar)
|
||||
ATTRACT_DIR=$(find_module attract)
|
||||
FLAMENCO_DIR=$(find_module flamenco)
|
||||
SVNMAN_DIR=$(find_module svnman)
|
||||
|
||||
echo "Pillar : $PILLAR_DIR"
|
||||
echo "Attract : $ATTRACT_DIR"
|
||||
echo "Flamenco: $FLAMENCO_DIR"
|
||||
echo "SVNMan : $SVNMAN_DIR"
|
||||
|
||||
if [ -z "$PILLAR_DIR" -o -z "$ATTRACT_DIR" -o -z "$FLAMENCO_DIR" -o -z "$SVNMAN_DIR" ];
|
||||
then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# SSH to cloud to pull all files in
|
||||
function git_pull() {
|
||||
PROJECT_NAME="$1"
|
||||
BRANCH="$2"
|
||||
REMOTE_ROOT="/data/git/${PROJECT_NAME}"
|
||||
|
||||
echo "==================================================================="
|
||||
echo "UPDATING FILES ON ${PROJECT_NAME}"
|
||||
${SSH} git -C ${REMOTE_ROOT} fetch origin ${BRANCH}
|
||||
${SSH} git -C ${REMOTE_ROOT} log origin/${BRANCH}..${BRANCH} --oneline
|
||||
${SSH} git -C ${REMOTE_ROOT} merge --ff-only origin/${BRANCH}
|
||||
}
|
||||
|
||||
git_pull pillar-python-sdk master
|
||||
git_pull pillar production
|
||||
git_pull attract production
|
||||
git_pull flamenco production
|
||||
git_pull pillar-svnman production
|
||||
git_pull blender-cloud production
|
||||
|
||||
# Update the virtualenv
|
||||
#${SSH} -t docker exec ${DOCKER_NAME} /data/venv/bin/pip install -U -r ${REMOTE_ROOT}/requirements.txt --exists-action w
|
||||
|
||||
# RSync the world
|
||||
$ATTRACT_DIR/rsync_ui.sh ${DEPLOYHOST}
|
||||
$FLAMENCO_DIR/rsync_ui.sh ${DEPLOYHOST}
|
||||
$SVNMAN_DIR/rsync_ui.sh ${DEPLOYHOST}
|
||||
./rsync_ui.sh ${DEPLOYHOST}
|
||||
|
||||
# Notify Sentry of this new deploy.
|
||||
# See https://sentry.io/blender-institute/blender-cloud/settings/release-tracking/
|
||||
# and https://docs.sentry.io/api/releases/post-organization-releases/
|
||||
# and https://sentry.io/api/
|
||||
echo
|
||||
echo "==================================================================="
|
||||
REVISION=$(date +'%Y%m%d.%H%M%S.%Z')
|
||||
echo "Notifying Sentry of this new deploy of revision ${REVISION}."
|
||||
SENTRY_RELEASE_URL="$(${SSH} python3 -c "\"import sys; sys.path.append('${REMOTE_ROOT}'); import config_local; print(config_local.SENTRY_RELEASE_URL)\"")"
|
||||
curl -vs "$SENTRY_RELEASE_URL" -XPOST -H 'Content-Type: application/json' -d "{\"version\": \"$REVISION\"}" | json_pp
|
||||
echo
|
||||
|
||||
# Wait for [ENTER] to restart the server
|
||||
echo
|
||||
echo "==================================================================="
|
||||
echo "NOTE: If you want to edit config_local.py on the server, do so now."
|
||||
echo "NOTE: Press [ENTER] to continue and restart the server process."
|
||||
read dummy
|
||||
echo "Gracefully restarting server process"
|
||||
${SSH} docker exec ${DOCKER_NAME} apache2ctl graceful
|
||||
echo "Server process restarted"
|
||||
|
||||
echo
|
||||
echo "==================================================================="
|
||||
echo "Restarting Celery worker."
|
||||
${SSH} docker restart ${CELERY_WORKER_DOCKER_NAME}
|
||||
echo "Celery worker docker restarted"
|
||||
echo "Restarting Celery beat."
|
||||
${SSH} docker restart ${CELERY_BEAT_DOCKER_NAME}
|
||||
echo "Celery beat docker restarted"
|
||||
|
||||
|
||||
echo
|
||||
echo "==================================================================="
|
||||
echo "Clearing front page from Redis cache."
|
||||
${SSH} docker exec redis redis-cli DEL pwview//
|
||||
|
||||
echo
|
||||
echo "==================================================================="
|
||||
echo "Deploy of ${PROJECT_NAME} is done."
|
||||
echo "==================================================================="
|
116
deploy/2docker.sh
Executable file
116
deploy/2docker.sh
Executable file
@@ -0,0 +1,116 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
DEPLOY_BRANCH=${DEPLOY_BRANCH:-production}
|
||||
|
||||
# macOS does not support readlink -f, so we use greadlink instead
|
||||
if [[ `uname` == 'Darwin' ]]; then
|
||||
command -v greadlink 2>/dev/null 2>&1 || { echo >&2 "Install greadlink using brew."; exit 1; }
|
||||
readlink='greadlink'
|
||||
else
|
||||
readlink='readlink'
|
||||
fi
|
||||
|
||||
ROOT="$(dirname "$(dirname "$($readlink -f "$0")")")"
|
||||
DEPLOYDIR="$ROOT/docker/4_run/deploy"
|
||||
PROJECT_NAME="$(basename $ROOT)"
|
||||
|
||||
if [ -e $DEPLOYDIR ]; then
|
||||
echo "$DEPLOYDIR already exists, press [ENTER] to DESTROY AND DEPLOY, Ctrl+C to abort."
|
||||
read dummy
|
||||
rm -rf $DEPLOYDIR
|
||||
else
|
||||
echo -n "Deploying to $DEPLOYDIR… "
|
||||
echo "press [ENTER] to continue, Ctrl+C to abort."
|
||||
read dummy
|
||||
fi
|
||||
|
||||
cd ${ROOT}
|
||||
mkdir -p $DEPLOYDIR
|
||||
REMOTE_ROOT="$DEPLOYDIR/$PROJECT_NAME"
|
||||
|
||||
if [ -z "$SKIP_BRANCH_CHECK" ]; then
|
||||
# Check that we're on production branch.
|
||||
if [ $(git rev-parse --abbrev-ref HEAD) != "$DEPLOY_BRANCH" ]; then
|
||||
echo "You are NOT on the $DEPLOY_BRANCH branch, refusing to deploy." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check that production branch has been pushed.
|
||||
if [ -n "$(git log origin/$DEPLOY_BRANCH..$DEPLOY_BRANCH --oneline)" ]; then
|
||||
echo "WARNING: not all changes to the $DEPLOY_BRANCH branch have been pushed."
|
||||
echo "Press [ENTER] to continue deploying current origin/$DEPLOY_BRANCH, CTRL+C to abort."
|
||||
read dummy
|
||||
fi
|
||||
fi
|
||||
|
||||
function find_module()
|
||||
{
|
||||
MODULE_NAME=$1
|
||||
MODULE_DIR=$(python <<EOT
|
||||
from __future__ import print_function
|
||||
import os.path
|
||||
try:
|
||||
import ${MODULE_NAME}
|
||||
except ImportError:
|
||||
raise SystemExit('${MODULE_NAME} not found on Python path. Are you in the correct venv?')
|
||||
|
||||
print(os.path.dirname(os.path.dirname(${MODULE_NAME}.__file__)))
|
||||
EOT
|
||||
)
|
||||
echo $MODULE_DIR
|
||||
}
|
||||
|
||||
# Find our modules
|
||||
echo "==================================================================="
|
||||
echo "LOCAL MODULE LOCATIONS"
|
||||
PILLAR_DIR=$(find_module pillar)
|
||||
ATTRACT_DIR=$(find_module attract)
|
||||
FLAMENCO_DIR=$(find_module flamenco)
|
||||
SVNMAN_DIR=$(find_module svnman)
|
||||
SDK_DIR=$(find_module pillarsdk)
|
||||
|
||||
echo "Pillar : $PILLAR_DIR"
|
||||
echo "Attract : $ATTRACT_DIR"
|
||||
echo "Flamenco: $FLAMENCO_DIR"
|
||||
echo "SVNMan : $SVNMAN_DIR"
|
||||
echo "SDK : $SDK_DIR"
|
||||
|
||||
if [ -z "$PILLAR_DIR" -o -z "$ATTRACT_DIR" -o -z "$FLAMENCO_DIR" -o -z "$SVNMAN_DIR" -o -z "$SDK_DIR" ];
|
||||
then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
function git_clone() {
|
||||
PROJECT_NAME="$1"
|
||||
BRANCH="$2"
|
||||
LOCAL_ROOT="$3"
|
||||
|
||||
echo "==================================================================="
|
||||
echo "CLONING REPO ON $PROJECT_NAME @$BRANCH"
|
||||
URL=$(git -C $LOCAL_ROOT remote get-url origin)
|
||||
git -C $DEPLOYDIR clone --depth 1 --branch $BRANCH $URL $PROJECT_NAME
|
||||
}
|
||||
|
||||
git_clone pillar-python-sdk master $SDK_DIR
|
||||
git_clone pillar $DEPLOY_BRANCH $PILLAR_DIR
|
||||
git_clone attract $DEPLOY_BRANCH $ATTRACT_DIR
|
||||
git_clone flamenco $DEPLOY_BRANCH $FLAMENCO_DIR
|
||||
git_clone pillar-svnman $DEPLOY_BRANCH $SVNMAN_DIR
|
||||
git_clone blender-cloud $DEPLOY_BRANCH $ROOT
|
||||
|
||||
# Gulp everywhere
|
||||
GULP=$ROOT/node_modules/.bin/gulp
|
||||
if [ ! -e $GULP -o gulpfile.js -nt $GULP ]; then
|
||||
npm install
|
||||
touch $GULP # installer doesn't always touch this after a build, so we do.
|
||||
fi
|
||||
$GULP --cwd $DEPLOYDIR/pillar --production
|
||||
$GULP --cwd $DEPLOYDIR/attract --production
|
||||
$GULP --cwd $DEPLOYDIR/flamenco --production
|
||||
$GULP --cwd $DEPLOYDIR/pillar-svnman --production
|
||||
$GULP --cwd $DEPLOYDIR/blender-cloud --production
|
||||
|
||||
echo
|
||||
echo "==================================================================="
|
||||
echo "Deploy of ${PROJECT_NAME} is ready for dockerisation."
|
||||
echo "==================================================================="
|
81
deploy/2server.sh
Executable file
81
deploy/2server.sh
Executable file
@@ -0,0 +1,81 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
# macOS does not support readlink -f, so we use greadlink instead
|
||||
if [[ `uname` == 'Darwin' ]]; then
|
||||
command -v greadlink 2>/dev/null 2>&1 || { echo >&2 "Install greadlink using brew."; exit 1; }
|
||||
readlink='greadlink'
|
||||
else
|
||||
readlink='readlink'
|
||||
fi
|
||||
ROOT="$(dirname "$(dirname "$($readlink -f "$0")")")"
|
||||
PROJECT_NAME="$(basename $ROOT)"
|
||||
DOCKER_DEPLOYDIR="$ROOT/docker/4_run/deploy"
|
||||
DOCKER_IMAGE="armadillica/blender_cloud:latest"
|
||||
REMOTE_SECRET_CONFIG_DIR="/data/config"
|
||||
REMOTE_DOCKER_COMPOSE_DIR="/root/docker"
|
||||
|
||||
#################################################################################
|
||||
case $1 in
|
||||
cloud*)
|
||||
DEPLOYHOST="$1"
|
||||
;;
|
||||
*)
|
||||
echo "Use $0 cloud{nr}|cloud.blender.org" >&2
|
||||
exit 1
|
||||
esac
|
||||
SSH_OPTS="-o ClearAllForwardings=yes -o PermitLocalCommand=no"
|
||||
SSH="ssh $SSH_OPTS $DEPLOYHOST"
|
||||
SCP="scp $SSH_OPTS"
|
||||
|
||||
echo -n "Deploying to $DEPLOYHOST… "
|
||||
|
||||
if ! ping $DEPLOYHOST -q -c 1 -W 2 >/dev/null; then
|
||||
echo "host $DEPLOYHOST cannot be pinged, refusing to deploy." >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
cat <<EOT
|
||||
[ping OK]
|
||||
|
||||
Make sure that you have pushed the $DOCKER_IMAGE
|
||||
docker image to Docker Hub.
|
||||
|
||||
press [ENTER] to continue, Ctrl+C to abort.
|
||||
EOT
|
||||
read dummy
|
||||
|
||||
#################################################################################
|
||||
echo "==================================================================="
|
||||
echo "Bringing remote Docker up to date…"
|
||||
$SSH mkdir -p $REMOTE_DOCKER_COMPOSE_DIR
|
||||
$SCP \
|
||||
$ROOT/docker/{docker-compose.yml,renew-letsencrypt.sh,mongo-backup.{cron,sh}} \
|
||||
$DEPLOYHOST:$REMOTE_DOCKER_COMPOSE_DIR
|
||||
$SSH -T <<EOT
|
||||
set -e
|
||||
cd $REMOTE_DOCKER_COMPOSE_DIR
|
||||
docker pull $DOCKER_IMAGE
|
||||
docker-compose up -d
|
||||
|
||||
echo
|
||||
echo "==================================================================="
|
||||
echo "Clearing front page from Redis cache."
|
||||
docker exec redis redis-cli DEL pwview//
|
||||
EOT
|
||||
|
||||
# Notify Sentry of this new deploy.
|
||||
# See https://sentry.io/blender-institute/blender-cloud/settings/release-tracking/
|
||||
# and https://docs.sentry.io/api/releases/post-organization-releases/
|
||||
# and https://sentry.io/api/
|
||||
echo
|
||||
echo "==================================================================="
|
||||
REVISION=$(date +'%Y%m%d.%H%M%S.%Z')
|
||||
echo "Notifying Sentry of this new deploy of revision $REVISION."
|
||||
SENTRY_RELEASE_URL="$($SSH env PYTHONPATH="$REMOTE_SECRET_CONFIG_DIR" python3 -c "\"import config_secrets; print(config_secrets.SENTRY_RELEASE_URL)\"")"
|
||||
curl -s "$SENTRY_RELEASE_URL" -XPOST -H 'Content-Type: application/json' -d "{\"version\": \"$REVISION\"}" | json_pp
|
||||
echo
|
||||
|
||||
echo
|
||||
echo "==================================================================="
|
||||
echo "Deploy to $DEPLOYHOST done."
|
||||
echo "==================================================================="
|
1
deploy/build-all.sh
Symbolic link
1
deploy/build-all.sh
Symbolic link
@@ -0,0 +1 @@
|
||||
build-quick.sh
|
34
deploy/build-quick.sh
Executable file
34
deploy/build-quick.sh
Executable file
@@ -0,0 +1,34 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
# macOS does not support readlink -f, so we use greadlink instead
|
||||
if [[ `uname` == 'Darwin' ]]; then
|
||||
command -v greadlink 2>/dev/null 2>&1 || { echo >&2 "Install greadlink using brew."; exit 1; }
|
||||
readlink='greadlink'
|
||||
else
|
||||
readlink='readlink'
|
||||
fi
|
||||
ROOT="$(dirname "$(dirname "$($readlink -f "$0")")")"
|
||||
DOCKERDIR="$ROOT/docker/4_run"
|
||||
|
||||
case "$(basename "$0")" in
|
||||
build-quick.sh)
|
||||
pushd "$ROOT/docker/4_run"
|
||||
./build.sh
|
||||
;;
|
||||
build-all.sh)
|
||||
pushd "$ROOT/docker"
|
||||
./full_rebuild.sh
|
||||
;;
|
||||
*)
|
||||
echo "Unknown script $0, aborting" >&2
|
||||
exit 1
|
||||
esac
|
||||
|
||||
popd
|
||||
echo
|
||||
echo "Press [ENTER] to push the new Docker image."
|
||||
read dummy
|
||||
docker push armadillica/blender_cloud:latest
|
||||
echo
|
||||
echo "Build is done, ready to update the server."
|
||||
|
@@ -1,4 +1,4 @@
|
||||
FROM ubuntu:16.10
|
||||
FROM ubuntu:17.10
|
||||
MAINTAINER Francesco Siddi <francesco@blender.org>
|
||||
|
||||
RUN apt-get update && apt-get install -qyy \
|
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Uses --no-cache to always get the latest upstream (security) upgrades.
|
||||
exec docker build --no-cache "$@" -t pillar_base -f base.docker .
|
||||
exec docker build --no-cache "$@" -t pillar_base .
|
||||
|
@@ -9,7 +9,7 @@ RUN sed -i 's/^# deb-src/deb-src/' /etc/apt/sources.list && \
|
||||
checkinstall \
|
||||
curl
|
||||
|
||||
RUN apt-get build-dep -y python3.5
|
||||
RUN apt-get build-dep -y python3.6
|
||||
|
||||
ADD Python-3.6.4.tar.xz.md5 /Python-3.6.4.tar.xz.md5
|
||||
|
||||
|
@@ -22,7 +22,7 @@ fi
|
||||
echo "Wheelhouse is $WHEELHOUSE"
|
||||
mkdir -p "$WHEELHOUSE"
|
||||
|
||||
docker build -t pillar_wheelbuilder -f build.docker .
|
||||
docker build -t pillar_wheelbuilder .
|
||||
|
||||
GID=$(id -g)
|
||||
docker run --rm -i \
|
||||
|
@@ -27,7 +27,6 @@ RUN mkdir -p $APACHE_RUN_DIR $APACHE_LOCK_DIR $APACHE_LOG_DIR
|
||||
ADD wheelhouse /data/wheelhouse
|
||||
RUN pip3 install --no-index --find-links=/data/wheelhouse -r /data/wheelhouse/requirements.txt
|
||||
|
||||
VOLUME /data/git
|
||||
VOLUME /data/config
|
||||
VOLUME /data/storage
|
||||
VOLUME /var/log
|
||||
@@ -37,12 +36,12 @@ ENV USE_X_SENDFILE True
|
||||
EXPOSE 80
|
||||
EXPOSE 5000
|
||||
|
||||
ADD wsgi-py36.* /etc/apache2/mods-available/
|
||||
ADD apache/wsgi-py36.* /etc/apache2/mods-available/
|
||||
RUN a2enmod rewrite && a2enmod wsgi-py36
|
||||
|
||||
ADD apache2.conf /etc/apache2/apache2.conf
|
||||
ADD 000-default.conf /etc/apache2/sites-available/000-default.conf
|
||||
ADD apache-logrotate.conf /etc/logrotate.d/apache2
|
||||
ADD apache/apache2.conf /etc/apache2/apache2.conf
|
||||
ADD apache/000-default.conf /etc/apache2/sites-available/000-default.conf
|
||||
ADD apache/logrotate.conf /etc/logrotate.d/apache2
|
||||
ADD *.sh /
|
||||
|
||||
# Remove some empty top-level directories we won't use anyway.
|
||||
@@ -53,3 +52,11 @@ RUN rmdir /media /home 2>/dev/null || true
|
||||
ADD bash_history /root/.bash_history
|
||||
|
||||
ENTRYPOINT /docker-entrypoint.sh
|
||||
|
||||
# Add the most-changing files as last step for faster rebuilds.
|
||||
ADD config_local.py /data/git/blender-cloud/
|
||||
ADD deploy /data/git
|
||||
RUN python3 -c "import re, secrets; \
|
||||
f = open('/data/git/blender-cloud/config_local.py', 'a'); \
|
||||
h = re.sub(r'[_.~-]', '', secrets.token_urlsafe())[:8]; \
|
||||
print(f'STATIC_FILE_HASH = {h!r}', file=f)"
|
@@ -1,11 +1,12 @@
|
||||
<VirtualHost *:80>
|
||||
XSendFile on
|
||||
XSendFilePath /data/storage/pillar
|
||||
XSendFilePath /data/git/pillar
|
||||
XSendFilePath /data/git/pillar/pillar/web/static/
|
||||
XSendFilePath /data/git/attract/attract/static/
|
||||
XSendFilePath /data/git/flamenco/flamenco/static/
|
||||
XsendFilePath /data/git/pillar-svnman/svnman/static/
|
||||
XsendFilePath /data/git/blender-cloud
|
||||
XsendFilePath /data/git/blender-cloud/static/
|
||||
XsendFilePath /data/git/blender-cloud/cloud/static/
|
||||
|
||||
ServerAdmin webmaster@localhost
|
||||
DocumentRoot /var/www/html
|
||||
@@ -19,7 +20,7 @@
|
||||
ErrorLog ${APACHE_LOG_DIR}/error.log
|
||||
CustomLog ${APACHE_LOG_DIR}/access.log combined
|
||||
|
||||
WSGIDaemonProcess cloud processes=2 threads=32 maximum-requests=10000
|
||||
WSGIDaemonProcess cloud processes=2 threads=64 maximum-requests=10000
|
||||
WSGIPassAuthorization On
|
||||
|
||||
WSGIScriptAlias / /data/git/blender-cloud/runserver.wsgi \
|
||||
@@ -47,5 +48,7 @@
|
||||
RewriteRule "^/textures/?$" "/p/textures" [R=301,L]
|
||||
RewriteRule "^/training/?$" "/courses" [R=301,L]
|
||||
RewriteRule "^/spring/?$" "/p/spring" [R=301,L]
|
||||
|
||||
RewriteRule "^/hero/?$" "/p/hero" [R=301,L]
|
||||
# Waking the forest was moved from the art gallery to its own workshop
|
||||
RewriteRule "^/p/gallery/58cfec4f88ac8f1440aeb309/?$" "/p/waking-the-forest" [R=301,L]
|
||||
</VirtualHost>
|
@@ -1,5 +1,5 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
docker build -t armadillica/blender_cloud:latest -f run.docker .
|
||||
docker build -t armadillica/blender_cloud:latest .
|
||||
|
||||
echo "Done, built armadillica/blender_cloud:latest"
|
||||
|
131
docker/4_run/config_local.py
Normal file
131
docker/4_run/config_local.py
Normal file
@@ -0,0 +1,131 @@
|
||||
import os
|
||||
from collections import defaultdict
|
||||
|
||||
DEBUG = False
|
||||
|
||||
SCHEME = 'https'
|
||||
PREFERRED_URL_SCHEME = 'https'
|
||||
SERVER_NAME = 'cloud.blender.org'
|
||||
|
||||
# os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = 'true'
|
||||
os.environ['PILLAR_MONGO_DBNAME'] = 'cloud'
|
||||
os.environ['PILLAR_MONGO_PORT'] = '27017'
|
||||
os.environ['PILLAR_MONGO_HOST'] = 'mongo'
|
||||
|
||||
USE_X_SENDFILE = True
|
||||
|
||||
STORAGE_BACKEND = 'gcs'
|
||||
|
||||
CDN_SERVICE_DOMAIN = 'blendercloud-pro.r.worldssl.net'
|
||||
CDN_CONTENT_SUBFOLDER = ''
|
||||
CDN_STORAGE_ADDRESS = 'push-11.cdnsun.com'
|
||||
|
||||
CACHE_TYPE = 'redis' # null
|
||||
CACHE_KEY_PREFIX = 'pw_'
|
||||
CACHE_REDIS_HOST = 'redis'
|
||||
CACHE_REDIS_PORT = '6379'
|
||||
CACHE_REDIS_URL = 'redis://redis:6379'
|
||||
|
||||
PILLAR_SERVER_ENDPOINT = 'https://cloud.blender.org/api/'
|
||||
|
||||
BLENDER_ID_ENDPOINT = 'https://www.blender.org/id'
|
||||
|
||||
GCLOUD_APP_CREDENTIALS = '/data/config/google_app.json'
|
||||
GCLOUD_PROJECT = 'blender-cloud'
|
||||
|
||||
MAIN_PROJECT_ID = '563a9c8cf0e722006ce97b03'
|
||||
# MAIN_PROJECT_ID = '57aa07c088bef606e89078bd'
|
||||
|
||||
ALGOLIA_INDEX_USERS = 'pro_Users'
|
||||
ALGOLIA_INDEX_NODES = 'pro_Nodes'
|
||||
|
||||
ZENCODER_NOTIFICATIONS_URL = 'https://cloud.blender.org/api/encoding/zencoder/notifications'
|
||||
|
||||
FILE_LINK_VALIDITY = defaultdict(
|
||||
lambda: 3600 * 24 * 30, # default of 1 month.
|
||||
gcs=3600 * 23, # 23 hours for Google Cloud Storage.
|
||||
cdnsun=3600 * 23
|
||||
)
|
||||
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'formatters': {
|
||||
'default': {'format': '%(levelname)8s %(name)s %(message)s'}
|
||||
},
|
||||
'handlers': {
|
||||
'console': {
|
||||
'class': 'logging.StreamHandler',
|
||||
'formatter': 'default',
|
||||
'stream': 'ext://sys.stderr',
|
||||
}
|
||||
},
|
||||
'loggers': {
|
||||
'pillar': {'level': 'INFO'},
|
||||
# 'pillar.auth': {'level': 'DEBUG'},
|
||||
# 'pillar.api.blender_id': {'level': 'DEBUG'},
|
||||
# 'pillar.api.blender_cloud.subscription': {'level': 'DEBUG'},
|
||||
'bcloud': {'level': 'INFO'},
|
||||
'cloud': {'level': 'INFO'},
|
||||
'attract': {'level': 'INFO'},
|
||||
'flamenco': {'level': 'INFO'},
|
||||
# 'pillar.api.file_storage': {'level': 'DEBUG'},
|
||||
# 'pillar.api.file_storage.ensure_valid_link': {'level': 'INFO'},
|
||||
'pillar.api.file_storage.refresh_links_for_backend': {'level': 'DEBUG'},
|
||||
'werkzeug': {'level': 'DEBUG'},
|
||||
'eve': {'level': 'WARNING'},
|
||||
# 'elasticsearch': {'level': 'DEBUG'},
|
||||
},
|
||||
'root': {
|
||||
'level': 'WARNING',
|
||||
'handlers': [
|
||||
'console',
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
REDIRECTS = {
|
||||
# For old links, refer to the services page (hopefully it refreshes then)
|
||||
'downloads/blender_cloud-latest-bundle.zip': 'https://cloud.blender.org/services#blender-addon',
|
||||
|
||||
# Latest Blender Cloud add-on; remember to update BLENDER_CLOUD_ADDON_VERSION.
|
||||
'downloads/blender_cloud-latest-addon.zip':
|
||||
'https://storage.googleapis.com/institute-storage/addons/blender_cloud-1.8.0.addon.zip',
|
||||
|
||||
# Redirect old Grafista endpoint to /stats
|
||||
'/stats/': '/stats',
|
||||
}
|
||||
|
||||
# Latest version of the add-on; remember to update REDIRECTS.
|
||||
BLENDER_CLOUD_ADDON_VERSION = '1.8.0'
|
||||
|
||||
UTM_LINKS = {
|
||||
'cartoon_brew': {
|
||||
'image': 'https://imgur.com/13nQTi3.png',
|
||||
'link': 'https://store.blender.org/product/membership/'
|
||||
}
|
||||
}
|
||||
|
||||
# Disabled until we have regenerated the majority of the links.
|
||||
CELERY_BEAT_SCHEDULE = {
|
||||
'regenerate-expired-links': {
|
||||
'task': 'pillar.celery.file_link_tasks.regenerate_all_expired_links',
|
||||
'schedule': 600, # every N seconds
|
||||
'args': ('gcs', 500)
|
||||
},
|
||||
}
|
||||
|
||||
SVNMAN_REPO_URL = 'https://svn.blender.cloud/repo/'
|
||||
SVNMAN_API_URL = 'https://svn.blender.cloud/api/'
|
||||
|
||||
# Mail options, see pillar.celery.email_tasks.
|
||||
SMTP_HOST = 'proog.blender.org'
|
||||
SMTP_PORT = 25
|
||||
SMTP_USERNAME = 'server@blender.cloud'
|
||||
SMTP_TIMEOUT = 30 # timeout in seconds, https://docs.python.org/3/library/smtplib.html#smtplib.SMTP
|
||||
MAIL_RETRY = 180 # in seconds, delay until trying to send an email again.
|
||||
MAIL_DEFAULT_FROM_NAME = 'Blender Cloud'
|
||||
MAIL_DEFAULT_FROM_ADDR = 'cloudsupport@blender.org'
|
||||
|
||||
# MUST be 8 characters long, see pillar.flask_extra.HashedPathConverter
|
||||
# STATIC_FILE_HASH = '12345678'
|
||||
# The value used in production is appended from Dockerfile.
|
@@ -1,18 +1,20 @@
|
||||
|
||||
if [ ! -f /installed ]; then
|
||||
SITEPKG=$(echo /opt/python/lib/python3.*/site-packages)
|
||||
echo "Installing Blender Cloud packages into $SITEPKG"
|
||||
|
||||
# TODO: 'pip3 install -e' runs 'setup.py develop', which runs 'setup.py egg_info',
|
||||
# which can't write the egg info to the read-only /data/git volume. This is why
|
||||
# we manually install the links.
|
||||
for SUBPROJ in /data/git/{pillar,pillar-python-sdk,attract,flamenco,pillar-svnman}; do
|
||||
NAME=$(python3 $SUBPROJ/setup.py --name)
|
||||
echo "... $NAME"
|
||||
echo $SUBPROJ >> $SITEPKG/easy-install.pth
|
||||
echo $SUBPROJ > $SITEPKG/$NAME.egg-link
|
||||
done
|
||||
echo "All packages installed."
|
||||
|
||||
touch /installed
|
||||
if [ -f /installed ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
SITEPKG=$(echo /opt/python/lib/python3.*/site-packages)
|
||||
echo "Installing Blender Cloud packages into $SITEPKG"
|
||||
|
||||
# TODO: 'pip3 install -e' runs 'setup.py develop', which runs 'setup.py egg_info',
|
||||
# which can't write the egg info to the read-only /data/git volume. This is why
|
||||
# we manually install the links.
|
||||
for SUBPROJ in /data/git/{pillar,pillar-python-sdk,attract,flamenco,pillar-svnman}; do
|
||||
NAME=$(python3 $SUBPROJ/setup.py --name)
|
||||
echo "... $NAME"
|
||||
echo $SUBPROJ >> $SITEPKG/easy-install.pth
|
||||
echo $SUBPROJ > $SITEPKG/$NAME.egg-link
|
||||
done
|
||||
echo "All packages installed."
|
||||
|
||||
touch /installed
|
||||
|
@@ -58,6 +58,7 @@ Place TLS certificates in `/data/certs/{cloud,cloudapi}.blender.org.pem`.
|
||||
They should contain (in order) the private key, the host certificate, and the
|
||||
CA certificate.
|
||||
|
||||
|
||||
## 6. Create a local config
|
||||
|
||||
Blender Cloud expects the following files to exist:
|
||||
@@ -65,6 +66,9 @@ Blender Cloud expects the following files to exist:
|
||||
- `/data/git/blender_cloud/config_local.py` with machine-local configuration overrides
|
||||
- `/data/config/google_app.json` with Google Cloud Storage credentials.
|
||||
|
||||
When run from Docker, the `docker/4_run/config_local.py` file will be used. Overrides for that file
|
||||
can be placed in `/data/config/config_secrets.py`.
|
||||
|
||||
|
||||
## 7. ElasticSearch & kibana
|
||||
|
||||
|
@@ -9,6 +9,11 @@ services:
|
||||
- /data/storage/db-bak:/data/db-bak # for backing up stuff etc.
|
||||
ports:
|
||||
- "127.0.0.1:27017:27017"
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "200k"
|
||||
max-file: "20"
|
||||
|
||||
redis:
|
||||
image: redis:3.2.8
|
||||
@@ -16,6 +21,11 @@ services:
|
||||
restart: always
|
||||
ports:
|
||||
- "127.0.0.1:6379:6379"
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "200k"
|
||||
max-file: "20"
|
||||
|
||||
rabbit:
|
||||
image: rabbitmq:3.6.10
|
||||
@@ -23,6 +33,11 @@ services:
|
||||
restart: always
|
||||
ports:
|
||||
- "127.0.0.1:5672:5672"
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "200k"
|
||||
max-file: "20"
|
||||
|
||||
elastic:
|
||||
image: armadillica/elasticsearch:6.1.1
|
||||
@@ -35,6 +50,11 @@ services:
|
||||
- "127.0.0.1:9200:9200"
|
||||
environment:
|
||||
ES_JAVA_OPTS: "-Xms256m -Xmx256m"
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "200k"
|
||||
max-file: "20"
|
||||
|
||||
elasticproxy:
|
||||
image: armadillica/elasticproxy:1.2
|
||||
@@ -43,6 +63,11 @@ services:
|
||||
command: /elasticproxy -elastic http://elastic:9200/
|
||||
depends_on:
|
||||
- elastic
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "200k"
|
||||
max-file: "20"
|
||||
|
||||
kibana:
|
||||
image: armadillica/kibana:6.1.1
|
||||
@@ -52,7 +77,7 @@ services:
|
||||
SERVER_NAME: "stats.cloud.blender.org"
|
||||
ELASTICSEARCH_URL: http://elasticproxy:9200
|
||||
CONSOLE_ENABLED: 'false'
|
||||
VIRTUAL_HOST: http://stats.cloud.blender.org/*,https://stats.cloud.blender.org/*,http://stats.blender-cloud/*,https://stats.blender-cloud/*
|
||||
VIRTUAL_HOST: http://stats.cloud.blender.org/*,https://stats.cloud.blender.org/*,http://stats.cloud.local/*,https://stats.cloud.local/*
|
||||
VIRTUAL_HOST_WEIGHT: 20
|
||||
FORCE_SSL: "true"
|
||||
|
||||
@@ -60,19 +85,24 @@ services:
|
||||
NODE_OPTIONS: "--max-old-space-size=200"
|
||||
depends_on:
|
||||
- elasticproxy
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "200k"
|
||||
max-file: "20"
|
||||
|
||||
blender_cloud:
|
||||
image: armadillica/blender_cloud:latest
|
||||
container_name: blender_cloud
|
||||
restart: always
|
||||
environment:
|
||||
VIRTUAL_HOST: http://cloud.blender.org/*,https://cloud.blender.org/*,http://blender-cloud/*,https://blender-cloud/*
|
||||
VIRTUAL_HOST: http://cloud.blender.org/*,https://cloud.blender.org/*,http://cloud.local/*,https://cloud.local/*
|
||||
VIRTUAL_HOST_WEIGHT: 10
|
||||
FORCE_SSL: "true"
|
||||
GZIP_COMPRESSION_TYPE: "text/html text/plain text/css application/javascript"
|
||||
PILLAR_CONFIG: /data/config/config_secrets.py
|
||||
volumes:
|
||||
# format: HOST:CONTAINER
|
||||
- /data/git:/data/git:ro
|
||||
- /data/config:/data/config:ro
|
||||
- /data/storage/pillar:/data/storage/pillar
|
||||
- /data/log:/var/log
|
||||
@@ -86,9 +116,10 @@ services:
|
||||
entrypoint: /celery-worker.sh
|
||||
container_name: celery_worker
|
||||
restart: always
|
||||
environment:
|
||||
PILLAR_CONFIG: /data/config/config_secrets.py
|
||||
volumes:
|
||||
# format: HOST:CONTAINER
|
||||
- /data/git:/data/git:ro
|
||||
- /data/config:/data/config:ro
|
||||
- /data/storage/pillar:/data/storage/pillar
|
||||
- /data/log:/var/log
|
||||
@@ -96,44 +127,44 @@ services:
|
||||
- mongo
|
||||
- redis
|
||||
- rabbit
|
||||
|
||||
celery_beat:
|
||||
image: armadillica/blender_cloud:latest
|
||||
entrypoint: /celery-beat.sh
|
||||
container_name: celery_beat
|
||||
restart: always
|
||||
volumes:
|
||||
# format: HOST:CONTAINER
|
||||
- /data/git:/data/git:ro
|
||||
- /data/storage/pillar:/data/storage/pillar
|
||||
- /data/log:/var/log
|
||||
depends_on:
|
||||
- mongo
|
||||
- redis
|
||||
- rabbit
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "200k"
|
||||
max-file: "20"
|
||||
|
||||
grafista:
|
||||
image: armadillica/grafista:latest
|
||||
container_name: grafista
|
||||
celery_beat:
|
||||
image: armadillica/blender_cloud:latest
|
||||
entrypoint: /celery-beat.sh
|
||||
container_name: celery_beat
|
||||
restart: always
|
||||
environment:
|
||||
PILLAR_CONFIG: /data/config/config_secrets.py
|
||||
volumes:
|
||||
- /data/git/grafista:/data/git/grafista:ro
|
||||
- /data/storage/grafista:/data/storage/grafista
|
||||
# format: HOST:CONTAINER
|
||||
- /data/config:/data/config:ro
|
||||
- /data/storage/pillar:/data/storage/pillar
|
||||
- /data/log:/var/log
|
||||
depends_on:
|
||||
- mongo
|
||||
- redis
|
||||
- rabbit
|
||||
- celery_worker
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "200k"
|
||||
max-file: "20"
|
||||
|
||||
letsencrypt:
|
||||
image: armadillica/picohttp:latest
|
||||
image: armadillica/picohttp:1.0
|
||||
container_name: letsencrypt
|
||||
restart: always
|
||||
environment:
|
||||
WEBROOT: /data/letsencrypt
|
||||
LISTEN: '[::]:80'
|
||||
VIRTUAL_HOST: http://cloud.blender.org/.well-known/*, http://stats.cloud.blender.org/.well-known/*
|
||||
VIRTUAL_HOST_WEIGHT: 20
|
||||
VIRTUAL_HOST_WEIGHT: 30
|
||||
volumes:
|
||||
- /data/letsencrypt:/data/letsencrypt
|
||||
|
||||
|
5
docker/mongo-backup.cron
Normal file
5
docker/mongo-backup.cron
Normal file
@@ -0,0 +1,5 @@
|
||||
# Change to suit your needs, then place in /etc/cron.d/mongo-backup
|
||||
# (so remove the .cron from the name)
|
||||
|
||||
MAILTO=yourname@youraddress.org
|
||||
30 5 * * * root /root/docker/mongo-backup.sh
|
28
docker/mongo-backup.sh
Executable file
28
docker/mongo-backup.sh
Executable file
@@ -0,0 +1,28 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
BACKUPDIR=/data/storage/db-bak
|
||||
DATE=$(date +'%Y-%m-%d-%H%M')
|
||||
ARCHIVE=$BACKUPDIR/mongo-live-$DATE.tar.xz
|
||||
|
||||
# Just a sanity check before we give it to 'rm -rf'
|
||||
if [ -z "$DATE" ]; then
|
||||
echo "Empty string found where the date should be, aborting."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
# /data/db-bak in Docker is /data/storage/db-bak on the host.
|
||||
docker exec mongo mongodump -d cloud \
|
||||
--out /data/db-bak/dump-$DATE \
|
||||
--excludeCollection tokens \
|
||||
--excludeCollection flamenco_task_logs \
|
||||
--quiet
|
||||
|
||||
cd $BACKUPDIR
|
||||
tar -Jcf $ARCHIVE dump-$DATE/
|
||||
rm -rf dump-$DATE
|
||||
|
||||
TO_DELETE="$(ls $BACKUPDIR/mongo-live-*.tar.xz | head -n -7)"
|
||||
[ -z "$TO_DELETE" ] || rm "$TO_DELETE"
|
||||
|
||||
rsync -a $BACKUPDIR/mongo-live-*.tar.xz cloud-backup@swami-direct.blender.cloud:
|
12
gulp
12
gulp
@@ -14,6 +14,18 @@ function install() {
|
||||
if [ "$1" == "watch" ]; then
|
||||
# Treat "gulp watch" as "gulp && gulp watch"
|
||||
$GULP
|
||||
elif [ "$1" == "all" ]; then
|
||||
# This is useful when building the Blender Cloud project for the first time.
|
||||
# Run "gulp" once inside the repo
|
||||
$GULP
|
||||
# Run ./gulp in all depending projects (pillar, attract, flamenco, pillar-svnman)
|
||||
declare -a repos=("pillar" "attract" "flamenco" "pillar-svnman")
|
||||
for r in "${repos[@]}"
|
||||
do
|
||||
cd ../$r
|
||||
./gulp
|
||||
done
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exec $GULP "$@"
|
||||
|
187
gulpfile.js
187
gulpfile.js
@@ -1,128 +1,113 @@
|
||||
var argv = require('minimist')(process.argv.slice(2));
|
||||
var autoprefixer = require('gulp-autoprefixer');
|
||||
var chmod = require('gulp-chmod');
|
||||
var concat = require('gulp-concat');
|
||||
var git = require('gulp-git');
|
||||
var gulp = require('gulp');
|
||||
var gulpif = require('gulp-if');
|
||||
var pug = require('gulp-pug');
|
||||
var livereload = require('gulp-livereload');
|
||||
var plumber = require('gulp-plumber');
|
||||
var rename = require('gulp-rename');
|
||||
var sass = require('gulp-sass');
|
||||
var sourcemaps = require('gulp-sourcemaps');
|
||||
var uglify = require('gulp-uglify');
|
||||
var cache = require('gulp-cached');
|
||||
let argv = require('minimist')(process.argv.slice(2));
|
||||
let autoprefixer = require('gulp-autoprefixer');
|
||||
let cache = require('gulp-cached');
|
||||
let concat = require('gulp-concat');
|
||||
let gulp = require('gulp');
|
||||
let gulpif = require('gulp-if');
|
||||
let pug = require('gulp-pug');
|
||||
let livereload = require('gulp-livereload');
|
||||
let plumber = require('gulp-plumber');
|
||||
let rename = require('gulp-rename');
|
||||
let sass = require('gulp-sass');
|
||||
let sourcemaps = require('gulp-sourcemaps');
|
||||
let uglify = require('gulp-uglify');
|
||||
|
||||
var enabled = {
|
||||
uglify: argv.production,
|
||||
maps: argv.production,
|
||||
failCheck: !argv.production,
|
||||
prettyPug: !argv.production,
|
||||
cachify: !argv.production,
|
||||
cleanup: argv.production,
|
||||
let enabled = {
|
||||
failCheck: !argv.production,
|
||||
maps: argv.production,
|
||||
prettyPug: !argv.production,
|
||||
uglify: argv.production
|
||||
};
|
||||
|
||||
var destination = {
|
||||
css: 'cloud/static/assets/css',
|
||||
pug: 'cloud/templates',
|
||||
js: 'cloud/static/assets/js',
|
||||
}
|
||||
|
||||
let destination = {
|
||||
css: 'cloud/static/assets/css',
|
||||
pug: 'cloud/templates',
|
||||
js: 'cloud/static/assets/js'
|
||||
};
|
||||
|
||||
/* CSS */
|
||||
gulp.task('styles', function() {
|
||||
gulp.src('src/styles/**/*.sass')
|
||||
.pipe(gulpif(enabled.failCheck, plumber()))
|
||||
.pipe(gulpif(enabled.maps, sourcemaps.init()))
|
||||
.pipe(sass({
|
||||
outputStyle: 'compressed'}
|
||||
))
|
||||
.pipe(autoprefixer("last 3 versions"))
|
||||
.pipe(gulpif(enabled.maps, sourcemaps.write(".")))
|
||||
.pipe(gulp.dest(destination.css))
|
||||
.pipe(gulpif(argv.livereload, livereload()));
|
||||
gulp.task('styles', function(done) {
|
||||
gulp
|
||||
.src('src/styles/**/*.sass')
|
||||
.pipe(gulpif(enabled.failCheck, plumber()))
|
||||
.pipe(gulpif(enabled.maps, sourcemaps.init()))
|
||||
.pipe(sass({outputStyle: 'compressed'}))
|
||||
.pipe(autoprefixer("last 3 versions"))
|
||||
.pipe(gulpif(enabled.maps, sourcemaps.write(".")))
|
||||
.pipe(gulp.dest(destination.css))
|
||||
.pipe(gulpif(argv.livereload, livereload()));
|
||||
done();
|
||||
});
|
||||
|
||||
|
||||
/* Templates - Pug */
|
||||
gulp.task('templates', function() {
|
||||
gulp.src('src/templates/**/*.pug')
|
||||
.pipe(gulpif(enabled.failCheck, plumber()))
|
||||
.pipe(gulpif(enabled.cachify, cache('templating')))
|
||||
.pipe(pug({
|
||||
pretty: enabled.prettyPug
|
||||
}))
|
||||
.pipe(gulp.dest(destination.pug))
|
||||
.pipe(gulpif(argv.livereload, livereload()));
|
||||
// TODO(venomgfx): please check why 'gulp watch' doesn't pick up on .txt changes.
|
||||
gulp.src('src/templates/**/*.txt')
|
||||
.pipe(gulpif(enabled.failCheck, plumber()))
|
||||
.pipe(gulpif(enabled.cachify, cache('templating')))
|
||||
.pipe(gulp.dest(destination.pug))
|
||||
.pipe(gulpif(argv.livereload, livereload()));
|
||||
gulp.task('templates', function(done) {
|
||||
gulp.src('src/templates/**/*.pug')
|
||||
.pipe(gulpif(enabled.failCheck, plumber()))
|
||||
.pipe(cache('templating'))
|
||||
.pipe(pug({
|
||||
pretty: enabled.prettyPug
|
||||
}))
|
||||
.pipe(gulp.dest(destination.pug))
|
||||
.pipe(gulpif(argv.livereload, livereload()));
|
||||
done();
|
||||
});
|
||||
|
||||
|
||||
/* Individual Uglified Scripts */
|
||||
gulp.task('scripts', function() {
|
||||
gulp.src('src/scripts/*.js')
|
||||
.pipe(gulpif(enabled.failCheck, plumber()))
|
||||
.pipe(gulpif(enabled.cachify, cache('scripting')))
|
||||
.pipe(gulpif(enabled.maps, sourcemaps.init()))
|
||||
.pipe(gulpif(enabled.uglify, uglify()))
|
||||
.pipe(rename({suffix: '.min'}))
|
||||
.pipe(gulpif(enabled.maps, sourcemaps.write(".")))
|
||||
.pipe(chmod(644))
|
||||
.pipe(gulp.dest(destination.js))
|
||||
.pipe(gulpif(argv.livereload, livereload()));
|
||||
/* Individually uglified scripts */
|
||||
gulp.task('scripts', function(done) {
|
||||
gulp.src('src/scripts/*.js')
|
||||
.pipe(gulpif(enabled.failCheck, plumber()))
|
||||
.pipe(cache('scripting'))
|
||||
.pipe(gulpif(enabled.maps, sourcemaps.init()))
|
||||
.pipe(gulpif(enabled.uglify, uglify()))
|
||||
.pipe(rename({suffix: '.min'}))
|
||||
.pipe(gulpif(enabled.maps, sourcemaps.write(".")))
|
||||
.pipe(gulp.dest(destination.js))
|
||||
.pipe(gulpif(argv.livereload, livereload()));
|
||||
done();
|
||||
});
|
||||
|
||||
|
||||
/* Collection of scripts in src/scripts/tutti/ to merge into tutti.min.js */
|
||||
/* Since it's always loaded, it's only for functions that we want site-wide */
|
||||
gulp.task('scripts_concat_tutti', function() {
|
||||
gulp.src('src/scripts/tutti/**/*.js')
|
||||
.pipe(gulpif(enabled.failCheck, plumber()))
|
||||
.pipe(gulpif(enabled.maps, sourcemaps.init()))
|
||||
.pipe(concat("tutti.min.js"))
|
||||
.pipe(gulpif(enabled.uglify, uglify()))
|
||||
.pipe(gulpif(enabled.maps, sourcemaps.write(".")))
|
||||
.pipe(chmod(644))
|
||||
.pipe(gulp.dest(destination.js))
|
||||
.pipe(gulpif(argv.livereload, livereload()));
|
||||
gulp.task('scripts_tutti', function(done) {
|
||||
gulp.src('src/scripts/tutti/**/*.js')
|
||||
.pipe(gulpif(enabled.failCheck, plumber()))
|
||||
.pipe(gulpif(enabled.maps, sourcemaps.init()))
|
||||
.pipe(concat("tutti.min.js"))
|
||||
.pipe(gulpif(enabled.uglify, uglify()))
|
||||
.pipe(gulpif(enabled.maps, sourcemaps.write(".")))
|
||||
.pipe(gulp.dest(destination.js))
|
||||
.pipe(gulpif(argv.livereload, livereload()));
|
||||
done();
|
||||
});
|
||||
|
||||
|
||||
/* Simply move these vendor scripts from node_modules */
|
||||
gulp.task('scripts_vendor', function(done) {
|
||||
let toMove = [
|
||||
'node_modules/photoswipe/dist/photoswipe.min.js'
|
||||
];
|
||||
gulp.src(toMove)
|
||||
.pipe(gulp.dest(destination.js));
|
||||
done();
|
||||
});
|
||||
|
||||
|
||||
// While developing, run 'gulp watch'
|
||||
gulp.task('watch',function() {
|
||||
// Only listen for live reloads if ran with --livereload
|
||||
if (argv.livereload){
|
||||
livereload.listen();
|
||||
}
|
||||
|
||||
gulp.watch('src/styles/**/*.sass',['styles']);
|
||||
gulp.watch('src/templates/**/*.pug',['templates']);
|
||||
gulp.watch('src/scripts/*.js',['scripts']);
|
||||
gulp.watch('src/scripts/tutti/**/*.js',['scripts_concat_tutti']);
|
||||
});
|
||||
|
||||
// Erases all generated files in output directories.
|
||||
gulp.task('cleanup', function() {
|
||||
var paths = [];
|
||||
for (attr in destination) {
|
||||
paths.push(destination[attr]);
|
||||
}
|
||||
|
||||
git.clean({ args: '-f -X ' + paths.join(' ') }, function (err) {
|
||||
if(err) throw err;
|
||||
});
|
||||
gulp.task('watch', function(done) {
|
||||
// Only reload the pages if we run with --livereload
|
||||
if (argv.livereload){
|
||||
livereload.listen();
|
||||
}
|
||||
|
||||
gulp.watch('src/styles/**/*.sass', gulp.series('styles'));
|
||||
gulp.watch('src/templates/**/*.pug', gulp.series('templates'));
|
||||
gulp.watch('src/scripts/*.js', gulp.series('scripts'));
|
||||
gulp.watch('src/scripts/tutti/*.js', gulp.series('scripts_tutti'));
|
||||
});
|
||||
|
||||
|
||||
// Run 'gulp' to build everything at once
|
||||
var tasks = [];
|
||||
if (enabled.cleanup) tasks.push('cleanup');
|
||||
gulp.task('default', tasks.concat(['styles', 'templates', 'scripts', 'scripts_concat_tutti']));
|
||||
gulp.task('default', gulp.series('styles', 'templates', 'scripts', 'scripts_tutti', 'scripts_vendor'));
|
||||
|
7325
package-lock.json
generated
Normal file
7325
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
32
package.json
32
package.json
@@ -7,20 +7,26 @@
|
||||
"url": "git://git.blender.org/blender-cloud.git"
|
||||
},
|
||||
"devDependencies": {
|
||||
"gulp": "~3.9.1",
|
||||
"gulp-autoprefixer": "~2.3.1",
|
||||
"gulp-cached": "~1.1.0",
|
||||
"gulp-chmod": "~1.3.0",
|
||||
"gulp-concat": "~2.6.0",
|
||||
"gulp-if": "^2.0.1",
|
||||
"gulp-git": "~2.4.2",
|
||||
"gulp-pug": "~3.2.0",
|
||||
"gulp": "^4.0.0",
|
||||
"gulp-autoprefixer": "~5.0.0",
|
||||
"gulp-cached": "~1.1.1",
|
||||
"gulp-chmod": "~2.0.0",
|
||||
"gulp-concat": "~2.6.1",
|
||||
"gulp-git": "~2.7.0",
|
||||
"gulp-if": "^2.0.2",
|
||||
"gulp-livereload": "~3.8.1",
|
||||
"gulp-plumber": "~1.1.0",
|
||||
"gulp-rename": "~1.2.2",
|
||||
"gulp-sass": "~2.3.1",
|
||||
"gulp-sourcemaps": "~1.6.0",
|
||||
"gulp-uglify": "~1.5.3",
|
||||
"gulp-plumber": "~1.2.0",
|
||||
"gulp-pug": "~4.0.1",
|
||||
"gulp-rename": "~1.3.0",
|
||||
"gulp-sass": "~4.0.1",
|
||||
"gulp-sourcemaps": "~2.6.4",
|
||||
"gulp-uglify": "~3.0.0",
|
||||
"minimist": "^1.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"bootstrap": "^4.1.2",
|
||||
"jquery": "^3.3.1",
|
||||
"popper.js": "^1.14.3",
|
||||
"photoswipe": "^4.1.2"
|
||||
}
|
||||
}
|
||||
|
91
rsync_ui.sh
91
rsync_ui.sh
@@ -1,91 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e # error out when one of the commands in the script errors.
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 {host-to-deploy-to}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
DEPLOYHOST="$1"
|
||||
|
||||
# macOS does not support readlink -f, so we use greadlink instead
|
||||
if [[ `uname` == 'Darwin' ]]; then
|
||||
command -v greadlink 2>/dev/null 2>&1 || { echo >&2 "Install greadlink using brew."; exit 1; }
|
||||
readlink='greadlink'
|
||||
else
|
||||
readlink='readlink'
|
||||
fi
|
||||
|
||||
BLENDER_CLOUD_DIR="$(dirname "$($readlink -f "$0")")"
|
||||
if [ ! -d "$BLENDER_CLOUD_DIR" ]; then
|
||||
echo "Unable to find Blender Cloud dir '$BLENDER_CLOUD_DIR'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BLENDER_CLOUD_ASSETS="$BLENDER_CLOUD_DIR/cloud/static/"
|
||||
BLENDER_CLOUD_TEMPLATES="$BLENDER_CLOUD_DIR/cloud/templates/"
|
||||
|
||||
if [ ! -d "$BLENDER_CLOUD_ASSETS" ]; then
|
||||
echo "Unable to find assets dir $BLENDER_CLOUD_ASSETS"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd $BLENDER_CLOUD_DIR
|
||||
if [ $(git rev-parse --abbrev-ref HEAD) != "production" ]; then
|
||||
echo "You are NOT on the production branch, refusing to rsync_ui." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PILLAR_DIR=$(python <<EOT
|
||||
from __future__ import print_function
|
||||
import os.path
|
||||
import pillar
|
||||
|
||||
print(os.path.dirname(os.path.dirname(pillar.__file__)))
|
||||
EOT
|
||||
)
|
||||
|
||||
PILLAR_ASSETS="$PILLAR_DIR/pillar/web/static/assets/"
|
||||
PILLAR_TEMPLATES="$PILLAR_DIR/pillar/web/templates/"
|
||||
|
||||
if [ ! -d "$PILLAR_ASSETS" ]; then
|
||||
echo "Unable to find assets dir $PILLAR_ASSETS"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd $PILLAR_DIR
|
||||
if [ $(git rev-parse --abbrev-ref HEAD) != "production" ]; then
|
||||
echo "Pillar is NOT on the production branch, refusing to rsync_ui." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "*** GULPA GULPA PILLAR ***"
|
||||
# TODO(Pablo): this command fails when passing the --production CLI
|
||||
# arg.
|
||||
./gulp
|
||||
|
||||
echo
|
||||
echo "*** SYNCING PILLAR_ASSETS ***"
|
||||
rsync -avh $PILLAR_ASSETS root@${DEPLOYHOST}:/data/git/pillar/pillar/web/static/assets/ --delete-after
|
||||
|
||||
echo
|
||||
echo "*** SYNCING PILLAR_TEMPLATES ***"
|
||||
rsync -avh $PILLAR_TEMPLATES root@${DEPLOYHOST}:/data/git/pillar/pillar/web/templates/ --delete-after
|
||||
|
||||
|
||||
cd $BLENDER_CLOUD_DIR
|
||||
|
||||
echo
|
||||
echo "*** GULPA GULPA BLENDER_CLOUD ***"
|
||||
./gulp --production
|
||||
|
||||
echo
|
||||
echo "*** SYNCING BLENDER_CLOUD_ASSETS ***"
|
||||
# Exclude files managed by Git.
|
||||
rsync -avh $BLENDER_CLOUD_ASSETS --exclude js/vendor/ root@${DEPLOYHOST}:/data/git/blender-cloud/cloud/static/ --delete-after
|
||||
|
||||
echo
|
||||
echo "*** SYNCING BLENDER_CLOUD_TEMPLATES ***"
|
||||
rsync -avh $BLENDER_CLOUD_TEMPLATES root@${DEPLOYHOST}:/data/git/blender-cloud/cloud/templates/ --delete-after
|
42
src/scripts/layout.js
Normal file
42
src/scripts/layout.js
Normal file
@@ -0,0 +1,42 @@
|
||||
/* Selectors
|
||||
================================================================== */
|
||||
var searchButton = document.querySelector('#searchButton'),
|
||||
searchCloseButton = document.querySelector('#searchCloseButton'),
|
||||
searchNav = document.querySelector('#searchNav'),
|
||||
searchNavInput = document.querySelector('#searchNav input'),
|
||||
navbarNav = document.querySelector('#navbarNav'),
|
||||
profileMenu = document.querySelector('#navbarNav .navbar-nav').lastElementChild
|
||||
|
||||
|
||||
/* Interactions
|
||||
================================================================== */
|
||||
searchButton.addEventListener('click', showSearch)
|
||||
searchCloseButton.addEventListener('click', closeSearch)
|
||||
searchNavInput.onblur = function() {
|
||||
closeSearch()
|
||||
}
|
||||
|
||||
|
||||
/* Functions
|
||||
================================================================== */
|
||||
function showSearch() {
|
||||
searchToggleStatus = true
|
||||
searchNav.classList.remove('hidden')
|
||||
searchNavInput.focus()
|
||||
navbarNav.classList.add('hidden')
|
||||
profileMenu.classList.add('visible')
|
||||
document.addEventListener('keyup', onPressEscCloseSearch)
|
||||
}
|
||||
|
||||
function closeSearch() {
|
||||
searchNav.classList.add('hidden')
|
||||
navbarNav.classList.remove('hidden')
|
||||
profileMenu.classList.remove('visible')
|
||||
document.removeEventListener('keyup', onPressEscCloseSearch)
|
||||
}
|
||||
|
||||
function onPressEscCloseSearch(e) {
|
||||
if (e.keyCode == 27) {
|
||||
closeSearch()
|
||||
}
|
||||
}
|
9
src/styles/_about.sass
Normal file
9
src/styles/_about.sass
Normal file
@@ -0,0 +1,9 @@
|
||||
section.team
|
||||
h2, .people-container
|
||||
text-align: center
|
||||
h3
|
||||
margin-bottom: 0
|
||||
h3 small
|
||||
display: block
|
||||
.people-intro, .row
|
||||
margin-bottom: 20px
|
8
src/styles/_breakpoints.sass
Normal file
8
src/styles/_breakpoints.sass
Normal file
@@ -0,0 +1,8 @@
|
||||
// Bootstrap Breakpoints
|
||||
// sm 576.98px
|
||||
// md 576px - 757.98px
|
||||
// lg 992px to 1199.98px
|
||||
// xl 1200px and up
|
||||
@import ../../static/assets/bootstrap/sass/functions
|
||||
@import ../../static/assets/bootstrap/sass/variables
|
||||
@import ../../static/assets/bootstrap/sass/mixins/breakpoints
|
36
src/styles/_cards.sass
Normal file
36
src/styles/_cards.sass
Normal file
@@ -0,0 +1,36 @@
|
||||
.container.card-container
|
||||
max-width: 1200px
|
||||
margin-top: 56px
|
||||
.col-md-4
|
||||
padding: 0 20px
|
||||
&:focus
|
||||
outline: none;
|
||||
.card
|
||||
border: none
|
||||
margin-bottom: 64px
|
||||
.card-image
|
||||
background-color: #ccc
|
||||
border-radius: 0
|
||||
height: 160px
|
||||
max-height: 160px
|
||||
min-height: 160px
|
||||
margin: 0 auto
|
||||
overflow: hidden
|
||||
width: 100%
|
||||
+media-breakpoint-up(sm)
|
||||
height: 203px
|
||||
max-height: 203px
|
||||
min-height: 203px
|
||||
img
|
||||
height: 100%
|
||||
object-fit: cover
|
||||
.card-title
|
||||
margin: 11px 0 5px
|
||||
font-size: 27px
|
||||
a
|
||||
color: #111
|
||||
text-decoration: none
|
||||
.card-text
|
||||
font-size: 18px
|
||||
.card-body
|
||||
padding: 0
|
9
src/styles/_colors.sass
Normal file
9
src/styles/_colors.sass
Normal file
@@ -0,0 +1,9 @@
|
||||
$primary: #0A68FF
|
||||
$grey: #EBEBEB
|
||||
$gray: #EBEBEB
|
||||
$dark: rgba(17,17,17,1)
|
||||
$muted: rgba(17,17,17,0.75)
|
||||
$lightgray: #F5F5F5
|
||||
// $theme-colors:
|
||||
// primary: red
|
||||
//
|
54
src/styles/_footer.sass
Normal file
54
src/styles/_footer.sass
Normal file
@@ -0,0 +1,54 @@
|
||||
@import ../styles/colors
|
||||
@import ../styles/breakpoints
|
||||
|
||||
footer.container-fluid
|
||||
background: #F8F8FB
|
||||
border-top: 1px solid #E3E3E6
|
||||
.container
|
||||
margin-top: 11px
|
||||
max-width: 1200px
|
||||
.row
|
||||
max-width: 1200px
|
||||
.col-4
|
||||
flex: 0 0 100%
|
||||
flex-basis: 100%
|
||||
max-width: 100%
|
||||
margin-bottom: 60px
|
||||
padding: 0 20px 56px
|
||||
+media-breakpoint-up(sm)
|
||||
padding: 0 20px 32px
|
||||
+media-breakpoint-up(md)
|
||||
flex: 0 0 33%
|
||||
padding-bottom: 0
|
||||
max-width: 33%
|
||||
margin-bottom: 0px
|
||||
.col
|
||||
flex-basis: 50%
|
||||
padding: 0 20px 32px
|
||||
+media-breakpoint-up(sm)
|
||||
flex-basis: 0
|
||||
padding-bottom: 0
|
||||
h5
|
||||
color: $dark
|
||||
font-weight: 600
|
||||
margin-bottom: 12px
|
||||
text-transform: uppercase
|
||||
p
|
||||
color: #6d6d6e
|
||||
font-size: 16px
|
||||
line-height: 30px
|
||||
.list-unstyled
|
||||
li
|
||||
line-height: 30px
|
||||
a
|
||||
color: #6d6d6e
|
||||
font-size: 16px
|
||||
&:hover
|
||||
color: #3F3F40
|
||||
.social-icons
|
||||
.list-inline-item:not(:last-child)
|
||||
margin-right: 22px
|
||||
a
|
||||
opacity: 1
|
||||
&:hover
|
||||
opacity: 0.8
|
56
src/styles/_gallery.sass
Normal file
56
src/styles/_gallery.sass
Normal file
@@ -0,0 +1,56 @@
|
||||
@import ../styles/colors
|
||||
@import ../styles/breakpoints
|
||||
|
||||
.gallery
|
||||
.cta-arrow
|
||||
margin-top: 20px
|
||||
.container
|
||||
max-width: 1190px
|
||||
padding: 0
|
||||
+media-breakpoint-up(sm)
|
||||
padding-right: 15px
|
||||
padding-left: 15px
|
||||
.thumbnail
|
||||
float: left
|
||||
position: relative
|
||||
width: 32.8%
|
||||
padding-bottom: 32.9%
|
||||
margin: 0.4%
|
||||
overflow: hidden
|
||||
// Fixes Thumbnail Spacing
|
||||
&:nth-of-type(1),
|
||||
&:nth-of-type(2),
|
||||
&:nth-of-type(3)
|
||||
margin-top: 0
|
||||
&:nth-of-type(1),
|
||||
&:nth-of-type(4),
|
||||
&:nth-of-type(7)
|
||||
margin-left: 0
|
||||
&:nth-of-type(3),
|
||||
&:nth-of-type(6)
|
||||
margin-right: 0
|
||||
+media-breakpoint-up(sm)
|
||||
width: 22.4%
|
||||
padding-bottom: 22.4%
|
||||
margin: 1.73%
|
||||
&:nth-of-type(4)
|
||||
margin-top: 0
|
||||
&:nth-of-type(1),
|
||||
&:nth-of-type(5)
|
||||
margin-left: 0
|
||||
&:nth-of-type(4),
|
||||
&:nth-of-type(7)
|
||||
margin-left: 1.73%
|
||||
&:nth-of-type(3),
|
||||
&:nth-of-type(6)
|
||||
margin-right: 1.73%
|
||||
&:nth-of-type(4),
|
||||
&:nth-of-type(8)
|
||||
margin-right: 0
|
||||
.thumbnail-container
|
||||
position: absolute
|
||||
width: 100%
|
||||
height: 100%
|
||||
img
|
||||
width: 300%
|
||||
transform: translate(-20%, -10%)
|
2
src/styles/_iframe.sass
Normal file
2
src/styles/_iframe.sass
Normal file
@@ -0,0 +1,2 @@
|
||||
.embed-responsive
|
||||
margin: 48px auto
|
32
src/styles/_jumbotron.sass
Normal file
32
src/styles/_jumbotron.sass
Normal file
@@ -0,0 +1,32 @@
|
||||
@import ../styles/colors
|
||||
@import ../styles/breakpoints
|
||||
|
||||
.jumbotron
|
||||
background-color: #fff
|
||||
background-repeat: no-repeat
|
||||
background-position: left top
|
||||
background-size: cover
|
||||
height: 360px
|
||||
width: 100%
|
||||
margin-bottom: 0px
|
||||
+media-breakpoint-up(md)
|
||||
height: 500px
|
||||
+media-breakpoint-up(xl)
|
||||
height: 600px
|
||||
.container
|
||||
max-width: 1160px
|
||||
display: flex
|
||||
height: 100%
|
||||
flex-direction: column
|
||||
justify-content: center
|
||||
h1.display-4
|
||||
color: white
|
||||
font-weight: 400
|
||||
font-size: 48px
|
||||
margin: 0
|
||||
text-shadow: 0 2px 2px rgba(0, 0, 0, 0.30)
|
||||
.lead
|
||||
max-width: 722px
|
||||
text-shadow: 0 2px 2px rgba(0, 0, 0, 0.80)
|
||||
p
|
||||
color: white
|
41
src/styles/_navbar-secondary.sass
Normal file
41
src/styles/_navbar-secondary.sass
Normal file
@@ -0,0 +1,41 @@
|
||||
@import ../styles/colors
|
||||
@import ../styles/breakpoints
|
||||
|
||||
.nav-scroller
|
||||
position: relative
|
||||
z-index: 2
|
||||
height: 2.75rem
|
||||
overflow-y: hidden
|
||||
.navbar-secondary
|
||||
max-width: 700px
|
||||
margin-bottom: 40px
|
||||
padding-left: 0
|
||||
border-bottom: 1px solid $gray
|
||||
+media-breakpoint-up(sm)
|
||||
margin-bottom: 56px
|
||||
.nav
|
||||
display: flex
|
||||
flex-wrap: nowrap
|
||||
overflow-x: auto
|
||||
text-align: center
|
||||
white-space: nowrap
|
||||
-webkit-overflow-scrolling: touch
|
||||
.nav-link
|
||||
font-size: 18px
|
||||
color: $dark
|
||||
padding: 13px 4px
|
||||
margin-right: 16px
|
||||
margin-left: 16px
|
||||
&:hover
|
||||
color: $muted
|
||||
.nav-title
|
||||
font-weight: 600
|
||||
@include media-breakpoint-up(md)
|
||||
padding-left: 0
|
||||
margin-left: 0
|
||||
&:hover
|
||||
color: $dark
|
||||
.active
|
||||
border-bottom: 2px solid $primary
|
||||
&:hover
|
||||
color: $dark
|
220
src/styles/_navbar.sass
Normal file
220
src/styles/_navbar.sass
Normal file
@@ -0,0 +1,220 @@
|
||||
@import ../styles/colors
|
||||
@import ../styles/breakpoints
|
||||
|
||||
nav.navbar
|
||||
background: #fff
|
||||
height: auto
|
||||
min-height: 48px
|
||||
padding: 2px 20px
|
||||
position: sticky
|
||||
+media-breakpoint-up(md)
|
||||
box-shadow: 0 2px 2px -2px rgba(0,0,0,.15)
|
||||
height: 56px
|
||||
padding: 10px 5px 10px 20px
|
||||
&.sticky-top
|
||||
+media-breakpoint-down(sm)
|
||||
position: static
|
||||
.navbar-brand
|
||||
padding: .3125rem 0
|
||||
z-index: 1002
|
||||
.navbar-toggler
|
||||
padding: 0
|
||||
border-radius: 0
|
||||
&:hover
|
||||
background: none
|
||||
.navbar-nav
|
||||
margin-bottom: 15px
|
||||
margin-top: 15px
|
||||
+media-breakpoint-up(md)
|
||||
margin: 0
|
||||
li
|
||||
line-height: 2.5
|
||||
.special
|
||||
top: 10px
|
||||
left: 35px
|
||||
a.navbar-item.active,
|
||||
a.navbar-item.active:hover,
|
||||
a.navbar-item:hover
|
||||
box-shadow: none
|
||||
li:last-of-type
|
||||
// profile menu
|
||||
z-index: 1002
|
||||
.dropdown-menu
|
||||
right: 0
|
||||
left: auto
|
||||
top: 54px
|
||||
padding: .5rem 0
|
||||
margin: .125rem 0 0
|
||||
&.visible
|
||||
visibility: visible
|
||||
li a
|
||||
padding: 0 15px 0 12px
|
||||
li:hover
|
||||
background-color: #f8f9fa
|
||||
.dropdown ul.dropdown-menu li a
|
||||
color: #111
|
||||
font-family: 'Source Sans Pro', sans-serif
|
||||
&:hover
|
||||
color: #111
|
||||
text-decoration: none
|
||||
.nav-item .nav-link
|
||||
font-size: 18px
|
||||
color: $dark
|
||||
padding: 10px
|
||||
+media-breakpoint-up(lg)
|
||||
padding: 6px 18px
|
||||
&:hover
|
||||
color: $primary
|
||||
.navbar-toggler
|
||||
border: 0
|
||||
display: block
|
||||
outline: none
|
||||
+media-breakpoint-up(md)
|
||||
display: none
|
||||
span
|
||||
width: 20px
|
||||
height: 2px
|
||||
background: $dark
|
||||
display: block
|
||||
margin-bottom: 4px
|
||||
&:last-of-type
|
||||
margin-bottom: 0
|
||||
.collapsing
|
||||
transition: none
|
||||
display: none
|
||||
#navbarNav
|
||||
animation-timing-function: cubic-bezier(0.4,0,0.2,1)
|
||||
animation-fill-mode: backwards
|
||||
opacity: 1
|
||||
transition: opacity .15s ease-in
|
||||
visibility: visible
|
||||
&.hidden
|
||||
animation-fill-mode: backwards
|
||||
animation-timing-function: cubic-bezier(0.4,0,0.2,1)
|
||||
opacity: 0
|
||||
transition: visibility 0s .15s, opacity .15s ease-in
|
||||
visibility: hidden
|
||||
.dropdown-toggle::after
|
||||
display:none !important
|
||||
&.show
|
||||
padding-bottom: 75vh
|
||||
.search-icon
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: center
|
||||
padding: 0 8px
|
||||
+media-breakpoint-up(lg)
|
||||
padding: 0 16px
|
||||
.pi-search
|
||||
&::before
|
||||
color: rgba(17,17,17,0.75)
|
||||
font-size: 16px
|
||||
&:hover
|
||||
color: $primary
|
||||
.nav-notifications
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: center
|
||||
padding: 0 8px
|
||||
+media-breakpoint-up(lg)
|
||||
padding: 0 16px
|
||||
.navbar-item
|
||||
height: auto
|
||||
padding: 0
|
||||
.active
|
||||
box-shadow: 0
|
||||
.flyout
|
||||
background-color: #fff
|
||||
background-clip: padding-box
|
||||
border: 1px solid rgba(0,0,0,.15)
|
||||
border-radius: .25rem
|
||||
box-shadow: 0
|
||||
font-size: 16px
|
||||
.flyout.notifications
|
||||
right: 65px
|
||||
top: 57px
|
||||
.nav-notifications:hover>#notifications-toggle
|
||||
display: block
|
||||
.nav-notifications-icon
|
||||
color: rgba(17,17,17,0.75)
|
||||
&:hover
|
||||
color: $primary
|
||||
.gravatar
|
||||
width: 32px
|
||||
border-radius: 50%
|
||||
.dropdown-menu
|
||||
margin-top: -1px
|
||||
border: 0
|
||||
border-radius: 0 0 4px 4px
|
||||
box-shadow: none
|
||||
font-size: 1rem
|
||||
color: #111
|
||||
text-align: left
|
||||
list-style: none
|
||||
background-color: #fff
|
||||
background-clip: padding-box
|
||||
box-shadow: 0px 4px 4px 0px hsla(0, 0%, 80%, 0.25)
|
||||
.dropdown:hover
|
||||
background: none
|
||||
&>.dropdown-menu
|
||||
display: block
|
||||
.dropdown-item
|
||||
color: #111
|
||||
font-size: 18px
|
||||
padding: 0px 15px
|
||||
i
|
||||
padding-right: 8px
|
||||
#userDropdown
|
||||
.nav-link
|
||||
padding-top: 4px
|
||||
padding-bottom: 0
|
||||
padding-right: 0
|
||||
outline: none
|
||||
#searchNav
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: center
|
||||
background-color: #fff
|
||||
max-height: 56px
|
||||
position: absolute
|
||||
width: calc(100% - 40px)
|
||||
z-index: 1001
|
||||
animation-timing-function: cubic-bezier(0.4,0,0.2,1)
|
||||
animation-fill-mode: backwards
|
||||
opacity: 1
|
||||
transition: opacity .15s ease-in
|
||||
visibility: visible
|
||||
+media-breakpoint-up(md)
|
||||
width: calc(100% - 25px)
|
||||
&.hidden
|
||||
animation-fill-mode: backwards
|
||||
animation-timing-function: cubic-bezier(0.4,0,0.2,1)
|
||||
opacity: 0
|
||||
transition: visibility 0s .15s, opacity .15s ease-in
|
||||
visibility: hidden
|
||||
.search-container
|
||||
position: relative
|
||||
max-width: 560px
|
||||
width: 100%
|
||||
input
|
||||
padding: 11px 20px 11px 46px
|
||||
color: #4d4e53
|
||||
box-shadow: none
|
||||
border: 1px solid #e5e5e5
|
||||
border-radius: 4px
|
||||
border-bottom-color: none
|
||||
background-color: #fcfcfc
|
||||
font-size: 18px
|
||||
transition: border-color 150ms ease-in-out, box-shadow 150ms ease-in-out
|
||||
width: 100%
|
||||
max-width: 560px
|
||||
.search-icon
|
||||
cursor: pointer
|
||||
position: absolute
|
||||
top: 14px
|
||||
left: 11px
|
||||
#searchCloseButton
|
||||
cursor: pointer
|
||||
position: absolute
|
||||
right: 16px
|
||||
top: 12px
|
43
src/styles/_typography.sass
Normal file
43
src/styles/_typography.sass
Normal file
@@ -0,0 +1,43 @@
|
||||
html
|
||||
// changing font-size here, will change all bootstrap font-sizes
|
||||
font-size: 20px
|
||||
body
|
||||
font-family: 'Source Sans Pro', sans-serif
|
||||
-webkit-font-smoothing: antialiased
|
||||
-moz-osx-font-smoothing: grayscale
|
||||
color: #212529
|
||||
h1, h2, h3, h4, h5
|
||||
font-family: 'Source Sans Pro', sans-serif
|
||||
margin-top: 0
|
||||
margin-bottom: .5rem
|
||||
h1
|
||||
font-size: 48px
|
||||
line-height: 57px
|
||||
font-weight: 500
|
||||
h2
|
||||
font-size: 36px
|
||||
line-height: 47px
|
||||
font-weight: 500
|
||||
h3
|
||||
font-size: 27px
|
||||
line-height: 38px
|
||||
font-weight: 500
|
||||
h4
|
||||
font-size 21px
|
||||
font-weight: 500
|
||||
line-height: 34px
|
||||
h5
|
||||
font-size: 15px
|
||||
letter-spacing: 0.6px
|
||||
p
|
||||
font-size: 20px
|
||||
line-height: 1.5
|
||||
margin-bottom: 1rem
|
||||
.lead
|
||||
font-size: 20px
|
||||
letter-spacing: 0.4px
|
||||
a
|
||||
color: #007bff
|
||||
&:hover
|
||||
color: #007bff
|
||||
text-decoration: underline
|
17
src/styles/base.sass
Normal file
17
src/styles/base.sass
Normal file
@@ -0,0 +1,17 @@
|
||||
/* mixins reused on every page
|
||||
================================================================== */
|
||||
@import ../styles/typography
|
||||
@import ../styles/navbar
|
||||
@import ../styles/footer
|
||||
|
||||
|
||||
/* Undo Old Base.css, main.css
|
||||
================================================================== */
|
||||
.container
|
||||
width: 100%
|
||||
padding-right: 15px
|
||||
padding-left: 15px
|
||||
margin-right: auto
|
||||
margin-left: auto
|
||||
.navbar+.page-content
|
||||
padding-top: 0
|
@@ -12,6 +12,7 @@
|
||||
@import _welcome
|
||||
@import _homepage
|
||||
@import _services
|
||||
@import _about
|
||||
@import ../../../pillar/src/styles/_search
|
||||
@import ../../../pillar/src/styles/_organizations
|
||||
|
||||
|
60
src/styles/project-landing.sass
Normal file
60
src/styles/project-landing.sass
Normal file
@@ -0,0 +1,60 @@
|
||||
@import ../styles/colors
|
||||
@import ../styles/breakpoints
|
||||
@import ../styles/jumbotron
|
||||
@import ../styles/navbar-secondary
|
||||
@import ../styles/iframe
|
||||
@import ../styles/gallery
|
||||
@import ../styles/cards
|
||||
|
||||
/* Undo main.css padding
|
||||
================================================================== */
|
||||
body,
|
||||
.container-page
|
||||
background: #fff
|
||||
section.node-details-container.project
|
||||
padding-bottom: 0
|
||||
.node-details-title
|
||||
padding-top: 0
|
||||
padding-bottom: 0
|
||||
|
||||
/* Override jumbotron to make it shorter than the default */
|
||||
.jumbotron
|
||||
height: 400px
|
||||
|
||||
/* Landing Page Sass
|
||||
================================================================== */
|
||||
.cta-arrow
|
||||
img
|
||||
padding-left: 11px
|
||||
.node-details-title
|
||||
&.container
|
||||
max-width: 1190px
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
ul,
|
||||
p
|
||||
max-width: 700px
|
||||
margin-left: auto
|
||||
margin-right: auto
|
||||
section
|
||||
margin-top: 104px
|
||||
+media-breakpoint-up(sm)
|
||||
margin-top: 152px
|
||||
&:first-child
|
||||
margin-top: 0
|
||||
h2
|
||||
margin-bottom: 24px
|
||||
+media-breakpoint-up(sm)
|
||||
margin-bottom: 40px
|
||||
.container.card-container
|
||||
margin-top: 0
|
||||
.card
|
||||
.card-image
|
||||
margin-top: 0
|
||||
footer.container-fluid
|
||||
margin-top: 72px
|
||||
+media-breakpoint-up(sm)
|
||||
margin-top: 112px
|
||||
+media-breakpoint-up(lg)
|
||||
margin-top: 136px
|
15
src/styles/projects-index-collection.sass
Normal file
15
src/styles/projects-index-collection.sass
Normal file
@@ -0,0 +1,15 @@
|
||||
@import ../styles/colors
|
||||
@import ../styles/breakpoints
|
||||
@import ../styles/jumbotron
|
||||
@import ../styles/navbar-secondary
|
||||
@import ../styles/cards
|
||||
|
||||
body,
|
||||
.container-page
|
||||
background: #fff
|
||||
footer.container-fluid
|
||||
margin-top: 72px
|
||||
+media-breakpoint-up(sm)
|
||||
margin-top: 112px
|
||||
+media-breakpoint-up(lg)
|
||||
margin-top: 136px
|
29
src/styles/welcome.sass
Normal file
29
src/styles/welcome.sass
Normal file
@@ -0,0 +1,29 @@
|
||||
@import ../styles/colors
|
||||
@import ../styles/breakpoints
|
||||
|
||||
nav.navbar
|
||||
+media-breakpoint-up(md)
|
||||
padding: 10px 10px 10px 20px
|
||||
.nav-item-sign-in
|
||||
line-height: 1.5
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: center
|
||||
.navbar-item
|
||||
.join .navbar .nav-item-sign-in a.navbar-item
|
||||
background: $primary
|
||||
font-size: 16px
|
||||
font-weight: 600
|
||||
margin: 0
|
||||
padding: 8px 16px
|
||||
width: 100%
|
||||
&:hover
|
||||
background: $primary
|
||||
+media-breakpoint-up(md)
|
||||
width: auto
|
||||
// temporarily restore old primary color
|
||||
h2,
|
||||
h3
|
||||
color: #68B3C8
|
||||
footer.container-fluid
|
||||
margin-top: 0
|
@@ -24,6 +24,148 @@ style.
|
||||
br
|
||||
| unique set of learning and creative resources.
|
||||
#page-content
|
||||
|
||||
section.team
|
||||
.container
|
||||
h2.
|
||||
Meet 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
|
||||
|
||||
.row
|
||||
.col-md-3
|
||||
a.face(
|
||||
href="https://twitter.com/tonroosendaal",
|
||||
data-blenderhead='ton')
|
||||
img(alt="Ton", src="{{ url_for('static', filename='assets/img/people/ton.jpg')}}")
|
||||
.bio
|
||||
h3 Ton Roosendaal
|
||||
small CEO Blender Foundation. Producer Blender Institute
|
||||
span The Netherlands
|
||||
.col-md-3
|
||||
a.face(
|
||||
href="https://twitter.com/fsiddi",
|
||||
data-blenderhead='francesco')
|
||||
img(alt="Francesco", src="{{ url_for('static', filename='assets/img/people/francesco.jpg')}}")
|
||||
.bio
|
||||
h3 Francesco Siddi
|
||||
small Pipeline Tools & Back-end Web Development
|
||||
span Italy
|
||||
.col-md-3
|
||||
a.face(
|
||||
href="https://twitter.com/hjalti",
|
||||
data-blenderhead='hjalti')
|
||||
img(alt="Hjalti", src="{{ url_for('static', filename='assets/img/people/hjalti.jpg')}}")
|
||||
.bio
|
||||
h3 Hjalti Hjálmarsson
|
||||
small Director. Animation. Layout.
|
||||
span Iceland
|
||||
.col-md-3
|
||||
a.face(
|
||||
href="https://twitter.com/PabloVazquez_",
|
||||
data-blenderhead='pablo')
|
||||
img(alt="Pablo", src="{{ url_for('static', filename='assets/img/people/pablo.jpg')}}")
|
||||
.bio
|
||||
h3 Pablo Vázquez
|
||||
small Lighting, Rendering. Front-end Web Development
|
||||
span Argentina
|
||||
.row
|
||||
.col-md-3
|
||||
a.face(
|
||||
href="https://twitter.com/artificial3d",
|
||||
data-blenderhead='andy')
|
||||
img(alt="Andy", src="{{ url_for('static', filename='assets/img/people/andy.jpg')}}")
|
||||
.bio
|
||||
h3 Andy Goralczyk
|
||||
small Shading, Lighting, Rendering, FX
|
||||
span Germany
|
||||
.col-md-3
|
||||
a.face(
|
||||
href="https://developer.blender.org/p/sergey/",
|
||||
data-blenderhead='sergey')
|
||||
img(alt="Sergey", src="{{ url_for('static', filename='assets/img/people/sergey.jpg')}}")
|
||||
.bio
|
||||
h3 Sergey Sharybin
|
||||
small Blender & Cycles Core Developer
|
||||
span Russia
|
||||
.col-md-3
|
||||
a.face(
|
||||
href="https://twitter.com/sastuvel",
|
||||
data-blenderhead='sybren')
|
||||
img(alt="Sybren", src="{{ url_for('static', filename='assets/img/people/sybren.jpg')}}")
|
||||
.bio
|
||||
h3 Sybren Stüvel
|
||||
small Blender Cloud Developer
|
||||
span The Netherlands
|
||||
.col-md-3
|
||||
a.face(
|
||||
href="https://twitter.com/dfelinto",
|
||||
data-blenderhead='dalai')
|
||||
img(alt="dalai", src="{{ url_for('static', filename='assets/img/people/dalai.jpg')}}")
|
||||
.bio
|
||||
h3 Dalai Felinto
|
||||
small Blender Developer
|
||||
span Brazil
|
||||
|
||||
.people-container.online
|
||||
.people-intro
|
||||
h3 Online Collaborators
|
||||
span Contributing to Blender Cloud from all over the globe.
|
||||
.row
|
||||
.col-md-3
|
||||
a.face(
|
||||
href="https://twitter.com/davidrevoy",
|
||||
data-blenderhead='david')
|
||||
img(alt="David", src="{{ url_for('static', filename='assets/img/people/david.jpg')}}")
|
||||
.bio
|
||||
h3 David Revoy
|
||||
small Illustrator & Concept Artist
|
||||
span France
|
||||
.col-md-3
|
||||
a.face(
|
||||
href="https://twitter.com/s_koenig",
|
||||
data-blenderhead='sebastian')
|
||||
img(alt="Sebastian", src="{{ url_for('static', filename='assets/img/people/sebastian.jpg')}}")
|
||||
.bio
|
||||
h3 Sebastian König
|
||||
small VFX
|
||||
span Germany
|
||||
.col-md-3
|
||||
a.face(
|
||||
href="https://twitter.com/gleb_alexandrov",
|
||||
data-blenderhead='gleb')
|
||||
img(alt="Gleb", src="{{ url_for('static', filename='assets/img/people/gleb.jpg')}}")
|
||||
.bio
|
||||
h3 Gleb Alexandrov
|
||||
small Lighting & Shading
|
||||
span Belarus
|
||||
.col-md-3
|
||||
a.face(
|
||||
href="https://twitter.com/the_mantissa",
|
||||
data-blenderhead='midge')
|
||||
img(alt="Midge", src="{{ url_for('static', filename='assets/img/people/midge.jpg')}}")
|
||||
.bio
|
||||
h3 Midge Sinnaeve
|
||||
small Motion Graphics
|
||||
span Belgium
|
||||
|
||||
.row
|
||||
.col-md-3
|
||||
a.face(
|
||||
href="https://twitter.com/jpbouza",
|
||||
data-blenderhead='jpbouza')
|
||||
img(alt="Juan Pablo", src="{{ url_for('static', filename='assets/img/people/jpbouza.jpg')}}")
|
||||
.bio
|
||||
h3 Juan Pablo Bouza
|
||||
small Rigging
|
||||
span Argentina
|
||||
|
||||
section.page-card
|
||||
h2 A bit of History
|
||||
section.page-card
|
||||
.page-card-side
|
||||
h2.page-card-title
|
||||
@@ -33,11 +175,11 @@ style.
|
||||
| First happy cloud video and crowdfunding for Cosmos Laundromat Pilot.
|
||||
.page-card-side
|
||||
a(href='https://gooseberry.blender.org/gooseberry-campaign-launched-we-need-10k-people-to-help/')
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2014_03_09_sxsw.jpg') }}")
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2014_03_09_sxsw.jpg') }}", alt="SXSW")
|
||||
section.page-card
|
||||
.page-card-side
|
||||
a(href='https://gooseberry.blender.org/gooseberry-campaign-launched-we-need-10k-people-to-help/')
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2014_03_10_cosmos.jpg') }}")
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2014_03_10_cosmos.jpg') }}", alt="Cosmos Laundromat")
|
||||
.page-card-side
|
||||
h2.page-card-title
|
||||
| Gooseberry | Cosmos Laundromat
|
||||
@@ -57,11 +199,11 @@ style.
|
||||
| .
|
||||
.page-card-side
|
||||
a(href='https://cloud.blender.org/p/glass-half/blog/glass-half-premiere')
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2015_10_30_glass.jpg') }}")
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2015_10_30_glass.jpg') }}", alt="Glass Half")
|
||||
section.page-card
|
||||
.page-card-side
|
||||
a(href='https://cloud.blender.org/blog/new-art-gallery-with-gleb-alexandrov')
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2015_11_19_art.jpg') }}")
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2015_11_19_art.jpg') }}", alt="Art Gallery")
|
||||
.page-card-side
|
||||
h2.page-card-title
|
||||
| Art Gallery
|
||||
@@ -77,11 +219,11 @@ style.
|
||||
| With so much going on in the Cloud at at the studio. The Blender Institute Podcast was born! Sharing our daily studio work, Blender community news, and interacting with the awesome Blender Cloud subscribers.
|
||||
.page-card-side
|
||||
a(href='https://cloud.blender.org/blog/introducing-blender-institute-podcast')
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2015_11_24_bip.jpg') }}")
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2015_11_24_bip.jpg') }}", alt="Blender Institute Podcast")
|
||||
section.page-card
|
||||
.page-card-side
|
||||
a(href='https://cloud.blender.org/p/blenrig/blog/welcome-to-the-blenrig-project')
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2015_12_01_blenrig.jpg') }}")
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2015_12_01_blenrig.jpg') }}", alt="Blenrig")
|
||||
.page-card-side
|
||||
h2.page-card-title
|
||||
| Blenrig
|
||||
@@ -97,11 +239,11 @@ style.
|
||||
| The biggest source for CC0/Public Domain textures on the interwebs goes live. First as beta, as a quick gift right before Xmas 2015!
|
||||
.page-card-side
|
||||
a(href='https://cloud.blender.org/blog/new-texture-library')
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2015_12_23_textures.jpg') }}")
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2015_12_23_textures.jpg') }}", alt="Texture Library")
|
||||
section.page-card
|
||||
.page-card-side
|
||||
a(href='https://cloud.blender.org/blog/nraryew-the-character-lib')
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2016_01_05_charlib.jpg') }}")
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2016_01_05_charlib.jpg') }}", alt="Character Library")
|
||||
.page-card-side
|
||||
h2.page-card-title
|
||||
| Character Library
|
||||
@@ -121,11 +263,11 @@ style.
|
||||
| .
|
||||
.page-card-side
|
||||
a(href='https://cloud.blender.org/p/caminandes-3/blog/caminandes-llamigos')
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2016_01_30_llamigos.jpg') }}")
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2016_01_30_llamigos.jpg') }}", alt="Caminandes: Llamigos")
|
||||
section.page-card
|
||||
.page-card-side
|
||||
a(href='https://cloud.blender.org/blog/welcome-sybren')
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2016_03_01_sybren.jpg') }}")
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2016_03_01_sybren.jpg') }}", alt="Dr. Sybren!")
|
||||
.page-card-side
|
||||
h2.page-card-title
|
||||
| Sybren
|
||||
@@ -141,11 +283,11 @@ style.
|
||||
| Create your own private projects on Blender Cloud.
|
||||
.page-card-side
|
||||
a(href='https://cloud.blender.org/blog/welcome-sybren')
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2016_05_03_projects.jpg') }}")
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2016_05_03_projects.jpg') }}", alt="Projects")
|
||||
section.page-card
|
||||
.page-card-side
|
||||
a(href='https://cloud.blender.org/blog/introducing-project-sharing')
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2016_05_09_projectsharing.jpg') }}")
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2016_05_09_projectsharing.jpg') }}", alt="Sharing")
|
||||
.page-card-side
|
||||
h2.page-card-title
|
||||
| Project Sharing
|
||||
@@ -161,11 +303,11 @@ style.
|
||||
| Browse the textures from within Blender!
|
||||
.page-card-side
|
||||
a(href='https://cloud.blender.org/blog/introducing-project-sharing')
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2016_05_11_addon.jpg') }}")
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2016_05_11_addon.jpg') }}", alt="Blender Cloud Add-on")
|
||||
section.page-card
|
||||
.page-card-side
|
||||
a(href='https://cloud.blender.org/blog/introducing-private-texture-libraries')
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2016_05_23_privtextures.jpg') }}")
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2016_05_23_privtextures.jpg') }}", alt="Texture Libraries")
|
||||
.page-card-side
|
||||
h2.page-card-title
|
||||
| Private Texture Libraries
|
||||
@@ -181,11 +323,11 @@ style.
|
||||
| Sync your Blender preferences across multiple devices.
|
||||
.page-card-side
|
||||
a(href='https://cloud.blender.org/blog/introducing-blender-sync')
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2016_06_30_sync.jpg') }}")
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2016_06_30_sync.jpg') }}", alt="Blender Sync")
|
||||
section.page-card
|
||||
.page-card-side
|
||||
a(href='https://cloud.blender.org/blog/introducing-image-sharing')
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2016_07_14_image.jpg') }}")
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2016_07_14_image.jpg') }}", alt="Image Sharing")
|
||||
.page-card-side
|
||||
h2.page-card-title
|
||||
| Image Sharing
|
||||
@@ -202,11 +344,11 @@ style.
|
||||
| High-dynamic range images are now available on Blender Cloud! With their own special viewer. Also available via the Blender Cloud add-on.
|
||||
.page-card-side
|
||||
a(href='https://cloud.blender.org/blog/introducing-the-hdri-library')
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2016_07_27_hdri.jpg') }}")
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2016_07_27_hdri.jpg') }}", alt="HDRI Library")
|
||||
section.page-card
|
||||
.page-card-side
|
||||
a(href='https://cloud.blender.org/blog/introducing-the-hdri-library')
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2016_12_06_toon.jpg') }}")
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2016_12_06_toon.jpg') }}", alt="Hdri Library")
|
||||
.page-card-side
|
||||
h2.page-card-title
|
||||
a(href='https://cloud.blender.org/blog/new-training-toon-character-workflow')
|
||||
@@ -225,5 +367,8 @@ style.
|
||||
a.page-card-cta(href='https://store.blender.org/product/membership/') Subscribe
|
||||
.page-card-side
|
||||
a(href='https://cloud.blender.org/p/agent-327')
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2017_03_10_agent.jpg') }}")
|
||||
img.img-responsive(src="{{ url_for('static_cloud', filename='img/2017_03_10_agent.jpg') }}", alt="Agent 327")
|
||||
|
||||
|
||||
|
||||
| {% endblock body%}
|
||||
|
@@ -29,34 +29,38 @@ html(lang="en")
|
||||
meta(name="twitter:image", content="{{ url_for('static', filename='assets/img/backgrounds/background_gleb_locomotive.jpg')}}")
|
||||
| {% endblock og %}
|
||||
|
||||
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/jquery-3.1.0.min.js', v=9112017)}}")
|
||||
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/jquery.typeahead-0.11.1.min.js', v=9112017)}}")
|
||||
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/js.cookie-2.0.3.min.js', v=9112017)}}")
|
||||
|
||||
script.
|
||||
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/jquery-3.1.0.min.js')}}")
|
||||
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/jquery.typeahead-0.11.1.min.js')}}")
|
||||
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/js.cookie-2.0.3.min.js')}}")
|
||||
| {% if current_user.is_authenticated %}
|
||||
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/clipboard.min.js')}}")
|
||||
| {% endif %}
|
||||
|
||||
| {% if current_user.has_cap('subscriber') %}
|
||||
| {# Only load if we can comment (for converting markdown as-we-type) #}
|
||||
script(src="{{ url_for('static_pillar', filename='assets/js/markdown.min.js', v=9112017) }}")
|
||||
script(src="{{ url_for('static_pillar', filename='assets/js/markdown.min.js') }}")
|
||||
| {% endif %}
|
||||
|
||||
script(src="{{ url_for('static_pillar', filename='assets/js/tutti.min.js', v=9112017) }}")
|
||||
script(src="{{ url_for('static_pillar', filename='assets/js/tutti.min.js') }}")
|
||||
|
||||
link(href="{{ url_for('static', filename='assets/img/favicon.png') }}", rel="shortcut icon")
|
||||
link(href="{{ url_for('static', filename='assets/img/apple-touch-icon-precomposed.png') }}", rel="icon apple-touch-icon-precomposed", sizes="192x192")
|
||||
|
||||
link(href="{{ url_for('static_pillar', filename='assets/css/vendor/bootstrap.min.css', v=9112017) }}", rel="stylesheet")
|
||||
link(href="{{ url_for('static', filename='assets/google-font-roboto/roboto.css', v=9112017) }}", rel="stylesheet")
|
||||
link(rel="stylesheet", href="{{ url_for('static', filename='assets/bootstrap/css/bootstrap.min.css') }}")
|
||||
link(href="{{ url_for('static_pillar', filename='assets/css/font-pillar.css') }}", rel="stylesheet")
|
||||
link(rel="stylesheet", href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,600")
|
||||
link(href="{{ url_for('static', filename='assets/google-font-roboto/roboto.css') }}", rel="stylesheet")
|
||||
|
||||
| {% block head %}{% endblock %}
|
||||
|
||||
| {% block css %}
|
||||
link(href="{{ url_for('static_pillar', filename='assets/css/font-pillar.css', v=9112017) }}", rel="stylesheet")
|
||||
link(href="{{ url_for('static_pillar', filename='assets/css/base.css', v=9112017) }}", rel="stylesheet")
|
||||
link(href="{{ url_for('static_pillar', filename='assets/css/font-pillar.css') }}", rel="stylesheet")
|
||||
link(href="{{ url_for('static_pillar', filename='assets/css/base.css') }}", rel="stylesheet")
|
||||
| {% if title == 'blog' %}
|
||||
link(href="{{ url_for('static_pillar', filename='assets/css/blog.css', v=9112017) }}", rel="stylesheet")
|
||||
link(href="{{ url_for('static_pillar', filename='assets/css/blog.css') }}", rel="stylesheet")
|
||||
| {% else %}
|
||||
link(href="{{ url_for('static', filename='cloud/assets/css/main.css', v=9112017) }}", rel="stylesheet")
|
||||
link(href="{{ url_for('static_cloud', filename='assets/css/main.css') }}", rel="stylesheet")
|
||||
link(href="{{ url_for('static_cloud', filename='assets/css/base.css') }}", rel="stylesheet")
|
||||
|
||||
| {% endif %}
|
||||
| {% endblock css %}
|
||||
|
||||
@@ -79,147 +83,86 @@ html(lang="en")
|
||||
| {% endif %}
|
||||
| {% endwith %}
|
||||
|
||||
nav.navbar
|
||||
.navbar-container
|
||||
header.navbar-header
|
||||
button.navbar-toggle(data-target=".navbar-collapse", data-toggle="collapse", type="button")
|
||||
span.sr-only Toggle navigation
|
||||
i.pi-menu
|
||||
a.navbar-brand(
|
||||
href="{{ url_for('main.homepage') }}",
|
||||
title="Blender Cloud")
|
||||
span.app-logo
|
||||
i.pi-blender-cloud
|
||||
|
||||
| {% block navigation_search %}
|
||||
.search-input
|
||||
input#cloud-search(
|
||||
type="text",
|
||||
placeholder="Search assets, tutorials...")
|
||||
//- Navigation Bar
|
||||
nav.navbar.navbar-expand-md.navbar-light.sticky-top
|
||||
//- Logo
|
||||
a.navbar-brand(href="{{ url_for('main.homepage') }}")
|
||||
img(src="{{ url_for('static', filename='assets/img/logo-blender-cloud-text.svg') }}", alt="alt")
|
||||
//- Mobile Nav Button
|
||||
button.navbar-toggler(type='button', data-toggle='collapse', data-target='#navbarNav', aria-controls="navbarNav", aria-expanded="false", aria-label="Toggle navigation")
|
||||
span
|
||||
span
|
||||
span
|
||||
//- Search Bar
|
||||
#searchNav.hidden
|
||||
span.search-container
|
||||
input#cloud-search(type="text", placeholder="Search Blender Cloud")
|
||||
i.search-icon.pi-search
|
||||
| {% endblock navigation_search %}
|
||||
a#searchCloseButton(ahref="#")
|
||||
img(src="{{ url_for('static', filename='assets/img/icons/icon-close-button.svg') }}", alt="alt")
|
||||
//- Links
|
||||
#navbarNav.collapse.navbar-collapse.justify-content-end
|
||||
ul.navbar-nav
|
||||
| {% if node and node.properties and node.properties.category %}
|
||||
| {% set category = node.properties.category %}
|
||||
| {% else %}
|
||||
| {% set category = title %}
|
||||
| {% endif %}
|
||||
|
||||
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.nav-item
|
||||
a.nav-link(href="{{ url_for('main.main_blog') }}", class="{% if category == 'blog' %}active{% endif %}") Blog
|
||||
li.nav-item.dropdown
|
||||
a.nav-link.dropdown-toggle(href="#", data-toggle="dropdown") Libraries
|
||||
.dropdown-menu
|
||||
a.dropdown-item(
|
||||
href="{{ url_for('projects.view', project_url='hdri') }}")
|
||||
i.pi-globe
|
||||
| HDRI
|
||||
a.dropdown-item(
|
||||
href="{{ url_for('projects.view', project_url='textures') }}")
|
||||
i.pi-folder-texture
|
||||
| Textures
|
||||
a.dropdown-item(
|
||||
href="{{ url_for('projects.view', project_url='characters') }}")
|
||||
i.pi-character
|
||||
| Characters
|
||||
li.nav-item.dropdown
|
||||
a.nav-link.dropdown-toggle(href="#", data-toggle="dropdown") Training
|
||||
.dropdown-menu
|
||||
a.dropdown-item(href="{{ url_for('cloud.courses') }}")
|
||||
i.pi-graduation-cap
|
||||
| Courses
|
||||
a.dropdown-item(href="{{ url_for('cloud.workshops') }}")
|
||||
i.pi-lightbulb
|
||||
| Workshops
|
||||
a.dropdown-item(href="{{ url_for('projects.view', project_url='gallery') }}")
|
||||
i.pi-image
|
||||
| Art Gallery
|
||||
li.nav-item
|
||||
a.nav-link(href="{{ url_for('cloud.open_projects') }}",
|
||||
class="{% if category in ['open-projects', 'film'] %}active{% endif %}") Open Projects
|
||||
li.nav-item
|
||||
a.nav-link(href="{{ url_for('cloud.services') }}",
|
||||
class="{% if category == 'services' %}active{% endif %}") Services
|
||||
|
||||
| {% 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.nav-item.search-icon
|
||||
a#searchButton.navbar-item(data-toggle='collpase', data-target='#searchbarNav', href="#")
|
||||
i.pi-search
|
||||
| {% endblock navigation_sections %}
|
||||
|
||||
li(class="dropdown libraries")
|
||||
a.navbar-item.dropdown-toggle(
|
||||
href="",
|
||||
data-toggle="dropdown",
|
||||
title="Libraries")
|
||||
span Libraries
|
||||
i.pi-angle-down
|
||||
| {% if current_user.is_anonymous %}
|
||||
li.nav-item
|
||||
a.nav-link(
|
||||
href="https://store.blender.org/product/membership/",
|
||||
title="Sign up") Sign up
|
||||
| {% endif %}
|
||||
|
||||
ul.dropdown-menu
|
||||
li
|
||||
a.navbar-item(
|
||||
href="{{ url_for('projects.view', project_url='hdri') }}",
|
||||
title="HDRI Library",
|
||||
data-toggle="tooltip",
|
||||
data-placement="left")
|
||||
i.pi-globe
|
||||
| HDRI
|
||||
li
|
||||
a.navbar-item(
|
||||
href="{{ url_for('projects.view', project_url='textures') }}",
|
||||
title="Textures Library",
|
||||
data-toggle="tooltip",
|
||||
data-placement="left")
|
||||
i.pi-folder-texture
|
||||
| Textures
|
||||
li
|
||||
a.navbar-item(
|
||||
href="{{ url_for('projects.view', project_url='characters') }}",
|
||||
title="Character Library",
|
||||
data-toggle="tooltip",
|
||||
data-placement="left")
|
||||
i.pi-character
|
||||
| Characters
|
||||
|
||||
|
||||
li(class="dropdown libraries")
|
||||
a.navbar-item.dropdown-toggle(
|
||||
href="",
|
||||
data-toggle="dropdown",
|
||||
title="Training")
|
||||
span Training
|
||||
i.pi-angle-down
|
||||
|
||||
ul.dropdown-menu
|
||||
li
|
||||
a.navbar-item(
|
||||
href="{{ url_for('cloud.courses') }}",
|
||||
title="Courses",
|
||||
data-toggle="tooltip",
|
||||
data-placement="left")
|
||||
i.pi-graduation-cap
|
||||
| Courses
|
||||
li
|
||||
a.navbar-item(
|
||||
href="{{ url_for('cloud.workshops') }}",
|
||||
title="Workshops",
|
||||
data-toggle="tooltip",
|
||||
data-placement="left")
|
||||
i.pi-lightbulb
|
||||
| Workshops
|
||||
li
|
||||
a.navbar-item(
|
||||
href="{{ url_for('projects.view', project_url='gallery') }}",
|
||||
title="Curated artwork collection",
|
||||
data-toggle="tooltip",
|
||||
data-placement="left")
|
||||
i.pi-image
|
||||
| Art Gallery
|
||||
|
||||
li
|
||||
a.navbar-item(
|
||||
href="{{ url_for('cloud.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('cloud.services') }}",
|
||||
title="Blender Cloud Services",
|
||||
data-toggle="tooltip",
|
||||
data-placement="bottom",
|
||||
class="{% if category == 'services' %}active{% endif %}")
|
||||
span Services
|
||||
| {% endblock navigation_sections %}
|
||||
|
||||
|
||||
| {% if current_user.is_anonymous %}
|
||||
li
|
||||
a.navbar-item(
|
||||
href="https://store.blender.org/product/membership/",
|
||||
title="Sign up") Sign up
|
||||
| {% endif %}
|
||||
|
||||
|
||||
| {% block navigation_user %}
|
||||
|
||||
| {% include 'menus/notifications.html' %}
|
||||
| {% include 'menus/user.html' %}
|
||||
|
||||
| {% endblock navigation_user %}
|
||||
| {% block navigation_user %}
|
||||
| {% include 'menus/notifications.html' %}
|
||||
| {% include 'menus/user.html' %}
|
||||
|
||||
| {% endblock navigation_user %}
|
||||
|
||||
.page-content
|
||||
#search-overlay
|
||||
@@ -230,81 +173,79 @@ html(lang="en")
|
||||
| {% block body %}{% endblock %}
|
||||
|
||||
| {% block footer_container %}
|
||||
#footer-container
|
||||
footer.container-fluid
|
||||
| {% 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
|
||||
.container.py-5
|
||||
.row
|
||||
.col-4
|
||||
h5 Blender Cloud
|
||||
p A creative hub for your projects, powered by free and open source software.
|
||||
ul.list-inline.social-icons
|
||||
li.list-inline-item
|
||||
a(href="https://www.facebook.com/BlenderCloudOfficial/")
|
||||
img(src="../../static/assets/img/icons/icon-social-facebook.svg", alt="alt")
|
||||
li.list-inline-item
|
||||
a(href="https://twitter.com/Blender_Cloud")
|
||||
img(src="../../static/assets/img/icons/icon-social-twitter.svg", alt="alt")
|
||||
li.list-inline-item
|
||||
a(href="https://www.youtube.com/channel/UC5qvW9fotdsSJkCguB_t-kQ")
|
||||
img(src="../../static/assets/img/icons/icon-social-youtube.svg", alt="alt")
|
||||
.col
|
||||
h5 Libraries
|
||||
ul.list-unstyled.text-small
|
||||
li
|
||||
a(href="{{ url_for('projects.view', project_url='hdri') }}") HDRI
|
||||
li
|
||||
a(href="{{ url_for('projects.view', project_url='textures') }}") Textures
|
||||
li
|
||||
a(href="{{ url_for('projects.view', project_url='characters') }}") Characters
|
||||
.col
|
||||
h5 Training
|
||||
ul.list-unstyled.text-small
|
||||
li
|
||||
a(href="{{ url_for('projects.view', project_url='gallery') }}") Art Gallery
|
||||
li
|
||||
a(href="{{ url_for('cloud.courses') }}") Courses
|
||||
li
|
||||
a(href="{{ url_for('cloud.workshops') }}") Workshops
|
||||
.col
|
||||
h5 Resources
|
||||
ul.list-unstyled.text-small
|
||||
li
|
||||
a(href="https://www.blender.org") Blender
|
||||
li
|
||||
a(href="https://store.blender.org/") Blender Store
|
||||
li
|
||||
a(href="https://www.blender.org/foundation/") Contact Us
|
||||
li
|
||||
a(href="{{ url_for('cloud.terms_and_conditions') }}") Terms and Conditions
|
||||
li
|
||||
a(href="{{ url_for('cloud.privacy') }}") Privacy
|
||||
.col
|
||||
h5 Services
|
||||
ul.list-unstyled.text-small
|
||||
li
|
||||
a(href="https://cloud.blender.org/services#attract") Attract
|
||||
li
|
||||
a(href="https://cloud.blender.org/services#blender-cloud-add-on") Blender Cloud Add-on
|
||||
li
|
||||
a(href="https://cloud.blender.org/services#blender-sync") Blender Sync
|
||||
li
|
||||
a(href="https://cloud.blender.org/services#flamenco") Flamenco
|
||||
li
|
||||
a(href="https://cloud.blender.org/services#image-sharing") Image Sharing
|
||||
li
|
||||
a(href="https://cloud.blender.org/services#projects") Private Projects
|
||||
li
|
||||
a(href="https://cloud.blender.org/services#texture-browser") Texture Browser
|
||||
|
||||
.col-md-2.col-xs-6
|
||||
ul.footer-social
|
||||
li
|
||||
a(href="https://www.facebook.com/BlenderCloudOfficial/",
|
||||
title="Follow us on Facebook")
|
||||
i.pi-social-facebook
|
||||
li
|
||||
a(href="https://twitter.com/Blender_Cloud",
|
||||
title="Follow us on Twitter")
|
||||
i.pi-social-twitter
|
||||
|
||||
.col-md-2.col-xs-6
|
||||
h4
|
||||
a(href="{{ url_for('main.homepage') }}")
|
||||
| Blender Cloud
|
||||
ul.footer-links
|
||||
li
|
||||
a(href="{{ url_for('main.main_blog') }}",
|
||||
title="Blender Cloud Blog")
|
||||
| Blog
|
||||
li
|
||||
a(href="{{ url_for('cloud.services') }}",
|
||||
title="Blender Cloud Services")
|
||||
| Services
|
||||
li
|
||||
a(href="{{ url_for('cloud.about') }}",
|
||||
title="About Blender Cloud")
|
||||
| About
|
||||
li
|
||||
a(href="{{ url_for('cloud.terms_and_conditions') }}",
|
||||
title="Terms and Conditions")
|
||||
| Terms and Conditions
|
||||
li
|
||||
a(href="{{ url_for('cloud.privacy') }}",
|
||||
title="Privacy")
|
||||
| Privacy
|
||||
|
||||
.col-md-2.col-xs-6
|
||||
h4
|
||||
a(href="https://www.blender.org",
|
||||
title="Blender official Website")
|
||||
| Blender
|
||||
ul.footer-links
|
||||
li
|
||||
a(href="https://www.blender.org",
|
||||
title="Blender official Website")
|
||||
| Blender.org
|
||||
li
|
||||
a(href="https://store.blender.org/",
|
||||
title="The official Blender Store")
|
||||
| Blender Store
|
||||
|
||||
.col-md-2.col-xs-6.special
|
||||
| With the support of the <br/> MEDIA Programme of the European Union<br/><br/>
|
||||
img(alt="MEDIA Programme of the European Union",
|
||||
src="https://gooseberry.blender.org/wp-content/uploads/2014/01/media_programme.png")
|
||||
| {% endblock footer_navigation %}
|
||||
|
||||
| {% block footer %}
|
||||
footer.container
|
||||
#hop(title="Be awesome in space")
|
||||
i.pi-angle-up
|
||||
| {% endblock footer %}
|
||||
//- Scroll Up Arrow. Not sure if it's necessary
|
||||
//- | {% block footer %}
|
||||
//- footer.container
|
||||
//- #hop(title="Be awesome in space")
|
||||
//- i.pi-angle-up
|
||||
//- | {% endblock footer %}
|
||||
| {% endblock footer_container %}
|
||||
|
||||
#notification-pop(data-url="", data-read-toggle="")
|
||||
@@ -320,7 +261,30 @@ html(lang="en")
|
||||
noscript
|
||||
link(href='//fonts.googleapis.com/css?family=Roboto:300,400', rel='stylesheet', type='text/css')
|
||||
|
||||
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/jquery.bootstrap-3.3.7.min.js', v=9112017) }}")
|
||||
//- script(src="{{ url_for('static_pillar', filename='assets/js/vendor/jquery.bootstrap-3.3.7.min.js') }}")
|
||||
|
||||
//- local bootstrap js returns error message, investigate later
|
||||
//- script(src="{{ url_for('static', filename='assets/jquery/jquery.slim.min.js') }}")
|
||||
//- script(src="{{ url_for('static', filename='assets/popper.js/popper.min.js') }}")
|
||||
//- script(src="{{ url_for('static', filename='assets/bootstrap/js/bootstrap.min.js') }}")
|
||||
script(src="https://code.jquery.com/jquery-3.3.1.min.js", integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=", crossorigin="anonymous")
|
||||
script(src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js", integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49", crossorigin="anonymous")
|
||||
script(src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.2/js/bootstrap.min.js", integrity="sha384-o+RDsa0aLu++PJvFqy8fFScvbHFLtbvScb8AjopnFD+iEQ7wo/CG0xlczd+2O/em", crossorigin="anonymous")
|
||||
script(src="{{ url_for('static_cloud', filename='assets/js/layout.min.js') }}")
|
||||
|
||||
| {% if current_user.is_authenticated %}
|
||||
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/jquery.typewatch-3.0.0.min.js') }}")
|
||||
script.
|
||||
// When sending an AJAX request, always add the X-CSRFToken header to it.
|
||||
var csrf_token = "{{ csrf_token() }}";
|
||||
$.ajaxSetup({
|
||||
beforeSend: function (xhr, settings) {
|
||||
if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) && !this.crossDomain) {
|
||||
xhr.setRequestHeader("X-CSRFToken", csrf_token);
|
||||
}
|
||||
}
|
||||
});
|
||||
| {% endif %}
|
||||
|
||||
script.
|
||||
$(document).ready(function() {
|
||||
|
@@ -9,7 +9,7 @@
|
||||
| {% endif %}
|
||||
|
||||
| {% block menu_avatar %}
|
||||
a.navbar-item.dropdown-toggle(href="#", data-toggle="dropdown", title="{{ current_user.email }}")
|
||||
a.nav-link.dropdown-toggle(href="#", data-toggle="dropdown", title="{{ current_user.email }}", aria-haspopup="true", aria-expanded="false")
|
||||
img.gravatar(
|
||||
src="{{ current_user.gravatar }}",
|
||||
class="{{ subscription }}",
|
||||
@@ -26,26 +26,26 @@ a.navbar-item.dropdown-toggle(href="#", data-toggle="dropdown", title="{{ curren
|
||||
|
||||
|
||||
| {% block menu_list %}
|
||||
li.subscription-status(class="{{ subscription }}")
|
||||
.dropdown-menu.subscription-status(class="{{ subscription }}", aria-labelledby="dropdownMenuLink")
|
||||
| {% if subscription == 'subscriber' %}
|
||||
a.navbar-item(
|
||||
a.dropdown-item(
|
||||
href="{{url_for('settings.billing')}}"
|
||||
title="View subscription info")
|
||||
i.pi-grin
|
||||
span Your subscription is active!
|
||||
| {% elif subscription == 'demo' %}
|
||||
a.navbar-item(
|
||||
a.dropdown-item(
|
||||
href="{{url_for('settings.billing')}}"
|
||||
title="View subscription info")
|
||||
i.pi-heart-filled
|
||||
span You have a free account.
|
||||
| {% elif current_user.has_cap('can-renew-subscription') %}
|
||||
a.navbar-item(target='_blank', href="/renew", title="Renew subscription")
|
||||
a.dropdown-item(target='_blank', href="/renew", title="Renew subscription")
|
||||
i.pi-heart
|
||||
span.info Your subscription is not active.
|
||||
span.renew Click here to renew.
|
||||
| {% else %}
|
||||
a.navbar-item(
|
||||
a.dropdown-item(
|
||||
href="https://store.blender.org/product/membership/"
|
||||
title="Renew subscription")
|
||||
i.pi-unhappy
|
||||
@@ -56,7 +56,7 @@ li.subscription-status(class="{{ subscription }}")
|
||||
| {{ super() }}
|
||||
|
||||
li
|
||||
a.navbar-item(
|
||||
a.dropdown-item(
|
||||
href="{{ url_for('settings.billing') }}"
|
||||
title="Billing")
|
||||
i.pi-credit-card
|
||||
|
190
src/templates/projects/landing.pug
Normal file
190
src/templates/projects/landing.pug
Normal file
@@ -0,0 +1,190 @@
|
||||
| {% import 'projects/_macros.html' as projectmacros %}
|
||||
| {% extends 'layout.html' %}
|
||||
|
||||
| {% 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) }}")
|
||||
meta(name="twitter:image", content="{{ og_picture.thumbnail('l', api=api) }}")
|
||||
| {% elif node and node.picture %}
|
||||
meta(property="og:image", content="{{ node.picture.thumbnail('l', api=api) }}")
|
||||
meta(name="twitter:image", content="{{ node.picture.thumbnail('l', api=api) }}")
|
||||
| {% elif project.picture_header %}
|
||||
meta(property="og:image", content="{{ project.picture_header.thumbnail('l', api=api) }}")
|
||||
meta(name="twitter:image", content="{{ project.picture_header.thumbnail('l', api=api) }}")
|
||||
| {% endif %}
|
||||
|
||||
| {% if show_project %}
|
||||
meta(property="og:title", content="{{ project.name }} - Blender Cloud")
|
||||
meta(name="twitter:title", content="{{ project.name }} - Blender Cloud")
|
||||
meta(property="og:description", content="{{ project.summary }}")
|
||||
meta(name="twitter:description", content="{{ project.summary }}")
|
||||
meta(property="og:url", content="{{ url_for('projects.view', project_url=project.url, _external=True) }}")
|
||||
| {% else %}
|
||||
|
||||
| {% if node %}
|
||||
meta(property="og:title", content="{{ node.name }} - Blender Cloud")
|
||||
meta(name="twitter:title", content="{{ node.name }} on Blender Cloud")
|
||||
|
||||
| {% if node.node_type == 'post' %}
|
||||
|
||||
| {% if node.properties.content %}
|
||||
meta(property="og:description", content="{{ node.properties.content | truncate(180) }}")
|
||||
meta(name="twitter:description", content="{{ node.properties.content | truncate(180) }}")
|
||||
| {% else %}
|
||||
meta(property="og:description", content="Blender Cloud, your source for open content and training")
|
||||
meta(name="twitter:description", content="Blender Cloud, your source for open content and training")
|
||||
| {% endif %}
|
||||
|
||||
| {% else %}
|
||||
|
||||
| {% if node.description %}
|
||||
meta(property="og:description", content="{{ node.description | truncate(180) }}")
|
||||
meta(name="twitter:description", content="{{ node.description | truncate(180) }}")
|
||||
| {% else %}
|
||||
meta(property="og:description", content="Blender Cloud, your source for open content and training")
|
||||
meta(name="twitter:description", content="Blender Cloud, your source for open content and training")
|
||||
| {% endif %}
|
||||
|
||||
| {% endif %}
|
||||
|
||||
meta(property="og:url", content="{{url_for('projects.view_node', project_url=project.url, node_id=node._id)}}")
|
||||
| {% else %}
|
||||
meta(property="og:title", content="{{ project.name }} Blog on Blender Cloud")
|
||||
meta(name="twitter:title", content="{{ project.name }} Blog on Blender Cloud")
|
||||
meta(property="og:description", content="{{ project.summary }}")
|
||||
meta(name="twitter:description", content="{{ project.summary }}")
|
||||
|
||||
meta(property="og:url", content="{{url_for('projects.view', project_url=project.url, _external=True)}}")
|
||||
| {% endif %}
|
||||
|
||||
| {% endif %}
|
||||
| {% endblock og %}
|
||||
|
||||
| {% block page_overlay %}
|
||||
#page-overlay.video
|
||||
.video-embed
|
||||
#others
|
||||
| {% endblock %}
|
||||
|
||||
| {% block head %}
|
||||
|
||||
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/videojs-6.2.8.min.js') }}")
|
||||
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/videojs-ga-0.4.2.min.js') }}")
|
||||
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/videojs-hotkeys-0.2.20.min.js') }}")
|
||||
script(src="{{ url_for('static_cloud', filename='assets/js/photoswipe.min.js') }}")
|
||||
| {% endblock %}
|
||||
|
||||
| {% block css %}
|
||||
| {{ super() }}
|
||||
link(href="{{ url_for('static_cloud', filename='assets/css/project-landing.css') }}", rel="stylesheet")
|
||||
| {% endblock %}
|
||||
|
||||
| {% block body %}
|
||||
header
|
||||
.jumbotron.jumbotron-fluid(
|
||||
style="background-image: url('{{ project.picture_header.thumbnail('h', api=api) }}'); background-position: 50% 50%;")
|
||||
|
||||
| {# Secondary Navigation #}
|
||||
| {% block navbar_secondary %}
|
||||
| {{ projectmacros.render_secondary_navigation(project, pages=pages) }}
|
||||
| {% endblock navbar_secondary %}
|
||||
|
||||
.container.landing
|
||||
section.node-details-container.project
|
||||
.node-details-title.container
|
||||
h1 {{ project.name }}
|
||||
|
||||
| {% if project.description %}
|
||||
| {{ project | markdowned('description') }}
|
||||
| {% endif %}
|
||||
|
||||
section.gallery
|
||||
h2.text-center Gallery
|
||||
.container
|
||||
| {% for n in activity_stream %}
|
||||
| {% if n.node_type not in ['comment', 'post'] and n.picture %}
|
||||
.thumbnail.expand-image-links
|
||||
.thumbnail-container
|
||||
a(href="{{ n.picture.thumbnail('l', api=api) }}", data-node_id="{{ n._id }}")
|
||||
img(src="{{ n.picture.thumbnail('l', api=api) }}", alt="{{ n.name }}")
|
||||
| {% endif %}
|
||||
| {% endfor %}
|
||||
.clearfix
|
||||
| {% if project.nodes_featured %}
|
||||
| {# In some cases featured_nodes might might be embedded #}
|
||||
| {% if '_id' in project.nodes_featured[0] %}
|
||||
| {% set featured_node_id=project.nodes_featured[0]._id %}
|
||||
| {% else %}
|
||||
| {% set featured_node_id=project.nodes_featured[0] %}
|
||||
| {% endif %}
|
||||
p.cta-arrow.text-center
|
||||
a(href="{{ url_for('projects.view_node', project_url=project.url, node_id=featured_node_id) }}")
|
||||
| See more
|
||||
i.pi-angle-right
|
||||
| {% endif %}
|
||||
|
||||
|
||||
|
||||
section.node-extra
|
||||
h2.text-center Latest Updates
|
||||
| {% if activity_stream %}
|
||||
.container.card-container
|
||||
.row
|
||||
| {% for n in activity_stream %}
|
||||
| {% if n.node_type == 'post' %}
|
||||
.col-md-4
|
||||
.card
|
||||
a.card-image(href="{{ url_for_node(node=n) }}")
|
||||
| {% if n.picture %}
|
||||
img.card-img-top(src="{{ n.picture.thumbnail('l', api=api) }}")
|
||||
| {% endif %}
|
||||
.card-body
|
||||
h4.card-title
|
||||
a(href="{{ url_for_node(node=n) }}") {{ n.name }}
|
||||
p.card-text {{ n.properties | markdowned('content') | striptags | truncate(140, end="... <small>read more</small>") | safe | hide_none }}
|
||||
| {% endif %}
|
||||
| {% endfor %}
|
||||
| {% endif %}
|
||||
.clearfix
|
||||
p.cta-arrow.text-center
|
||||
a(href="{{ url_for('main.project_blog', project_url=project.url) }}")
|
||||
| See all updates
|
||||
i.pi-angle-right
|
||||
|
||||
| {% endblock body %}
|
||||
|
||||
|
||||
| {% 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[data-node_id]").on( "click", function(e) {
|
||||
// var nodeId = $(this).data('node_id');
|
||||
// displayNode(nodeId);
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
$('#page-overlay').addClass('active');
|
||||
var url = $(this).attr('href');
|
||||
$('#page-overlay').html('<img src="' + url + '"/>')
|
||||
});
|
||||
|
||||
|
||||
| {% endblock %}
|
@@ -3,20 +3,20 @@
|
||||
| {# Default case is Open Projects #}
|
||||
| {% set page_title = 'Open Projects' %}
|
||||
| {% set page_description = 'Full production data and tutorials from all open movies, for you to use freely' %}
|
||||
| {% set page_header_image = url_for('static', filename='assets/img/backgrounds/background_agent327_01.jpg') %}
|
||||
| {% set page_header_text = 'The iconic Blender Institute Open Movies. Featuring all the production files, assets, artwork, and never-seen-before content.' %}
|
||||
| {% set page_header_image = url_for('static', filename='assets/img/backgrounds/banner-open-projects.jpg') %}
|
||||
| {% set page_header_text = 'See how each film came to be. Explore our production files, assets, artwork and more. Get full access to behind the scenes at the Blender Animation Studio. Follow along as we share our process and techniques for each movie.' %}
|
||||
|
||||
| {% if title == 'courses' %}
|
||||
| {% set page_title = 'Courses' %}
|
||||
| {% if title == 'courses' or title == 'workshops' %}
|
||||
| {% set page_title = 'Training' %}
|
||||
| {% set page_description = 'Production quality training by 3D professionals' %}
|
||||
| {% set page_header_image = url_for('static', filename='assets/img/backgrounds/background_caminandes_3_03.jpg') %}
|
||||
| {% set page_header_text = 'Character modeling, 3D printing, VFX, rigging and more.' %}
|
||||
| {% set page_header_image = url_for('static', filename='assets/img/backgrounds/banner-training.jpg') %}
|
||||
| {% set page_header_text = 'Browse through our structured courses. Choose a workshop where top Blender Artists walk you through professional techniques to build a specific project. Visit the Art Gallery where you can download and study source files from your favorite artists.' %}
|
||||
|
||||
| {% elif title == 'workshops' %}
|
||||
| {% set page_title = 'Workshops' %}
|
||||
| {% set page_description = 'Production quality training by 3D professionals' %}
|
||||
| {% set page_header_image = url_for('static', filename='assets/img/backgrounds/background_caminandes_3_03.jpg') %}
|
||||
| {% set page_header_text = 'Enter the artist workshop and learn by example.' %}
|
||||
//- | {% elif title == 'workshops' %}
|
||||
//- | {% set page_title = 'Workshops' %}
|
||||
//- | {% set page_description = 'Production quality training by 3D professionals' %}
|
||||
//- | {% set page_header_image = url_for('static', filename='assets/img/backgrounds/background_caminandes_3_03.jpg') %}
|
||||
//- | {% set page_header_text = 'Enter the artist workshop and learn by example.' %}
|
||||
|
||||
| {% endif %}
|
||||
|
||||
@@ -33,6 +33,10 @@ meta(name="twitter:description", content="{{ page_description }}")
|
||||
meta(property="og:image", content="{{ page_header_image }}")
|
||||
meta(name="twitter:image", content="{{ page_header_image }}")
|
||||
| {% endblock %}
|
||||
| {% block css %}
|
||||
| {{ super() }}
|
||||
link(href="{{ url_for('static_cloud', filename='assets/css/projects-index-collection.css') }}", rel="stylesheet")
|
||||
| {% endblock css %}
|
||||
|
||||
| {% block page_title %}
|
||||
| {{ page_title }}
|
||||
@@ -40,58 +44,63 @@ meta(name="twitter:image", content="{{ page_header_image }}")
|
||||
|
||||
| {% block body %}
|
||||
|
||||
#project-container
|
||||
//- Jumbotron
|
||||
.jumbotron.jumbotron-fluid(style="background-image: url('{{ page_header_image }}')")
|
||||
.container
|
||||
h1.display-4.node_index-collection-name {{ page_title }}
|
||||
p.lead.node_index-collection-description {{ page_header_text }}
|
||||
//- Secondary Navigation
|
||||
| {% if title == 'courses' or title == 'workshops' %}
|
||||
.container.navbar-secondary
|
||||
ul.nav.justify-content-left
|
||||
li.nav-item
|
||||
a.nav-link.nav-title(href="#") Training
|
||||
li.nav-item
|
||||
a.nav-link(href="#", class="{% if title == 'courses' %}active{% endif %}") Courses
|
||||
li.nav-item
|
||||
a.nav-link(href="#", class="{% if title == 'workshops' %}active{% endif %}") Workshops
|
||||
li.nav-item
|
||||
a.nav-link(href="#") Art Gallery
|
||||
| {% endif %}
|
||||
//- Project Cards
|
||||
.container.card-container
|
||||
.row
|
||||
| {% 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-container
|
||||
#node_index-header.collection
|
||||
img.background-header(src="{{ page_header_image }}")
|
||||
#node_index-collection-info
|
||||
.node_index-collection-name
|
||||
span {{ page_title }}
|
||||
.node_index-collection-description
|
||||
span.
|
||||
{{ page_header_text }}
|
||||
|
||||
.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 }}")
|
||||
.col-md-4(
|
||||
data-url="{{ url_for('projects.view', project_url=project.url) }}",
|
||||
tabindex="{{ loop.index }}")
|
||||
.card
|
||||
| {% if project.picture_header %}
|
||||
a.item-header(
|
||||
href="{{ url_for('projects.view', project_url=project.url) }}")
|
||||
img(src="{{ project.picture_header.thumbnail('l', api=api) }}")
|
||||
a.card-image(href="{{ url_for('projects.view', project_url=project.url) }}")
|
||||
img.card-img-top(src="{{ project.picture_header.thumbnail('l', api=api) }}")
|
||||
| {% endif %}
|
||||
|
||||
.item-info
|
||||
a.item-title(
|
||||
href="{{ url_for('projects.view', project_url=project.url) }}")
|
||||
| {{project.name}}
|
||||
| {% if project.status == 'pending' and current_user.is_authenticated and current_user.has_role('admin') %}
|
||||
small (pending)
|
||||
| {% endif %}
|
||||
.card-body
|
||||
h4.card-title
|
||||
a(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
|
||||
p.card-text
|
||||
| {{project.summary|safe}}
|
||||
| {% endif %}
|
||||
|
||||
a.learn-more LEARN MORE
|
||||
|
||||
| {% endif %}
|
||||
| {% endfor %}
|
||||
| {% endif %}
|
||||
| {% endfor %}
|
||||
|
||||
|
||||
| {% endblock %}
|
||||
|
||||
|
||||
| {% block footer_scripts %}
|
||||
script.
|
||||
$('.node_index-collection-card.project').on('click', function(e){
|
||||
e.preventDefault();
|
||||
window.location.href = $(this).data('url');
|
||||
});
|
||||
//- script.
|
||||
//- $('.node_index-collection-card.project').on('click', function(e){
|
||||
//- e.preventDefault();
|
||||
//- window.location.href = $(this).data('url');
|
||||
//- });
|
||||
| {% endblock %}
|
||||
|
@@ -53,7 +53,7 @@ h4 Thank you for supporting us!
|
||||
hr
|
||||
p Subscription expires on: <strong>{{ expiration_date }}</strong>
|
||||
p
|
||||
a(href="{{ config['EXTERNAL_SUBSCRIPTIONS_MANAGEMENT_SERVER'] | urljoin('my-account/subscriptions/') }}") Manage your subscription on Blender Store
|
||||
a(href="{{ config['EXTERNAL_SUBSCRIPTIONS_MANAGEMENT_SERVER'] | urljoin('/my-account/subscriptions/') }}") Manage your subscription on Blender Store
|
||||
|
||||
//---------------------------------
|
||||
| {% elif user_cls == 'subscriber-org' %}
|
||||
|
@@ -11,6 +11,10 @@ meta(property="og:title", content="Blender Cloud - Open Content Production Platf
|
||||
meta(property="og:url", content="https://cloud.blender.org/")
|
||||
meta(property="og:image", content="{{ url_for('static', filename='assets/img/backgrounds/background_dweebs_01.jpg')}}")
|
||||
| {% endblock og %}
|
||||
| {% block css %}
|
||||
| {{ super() }}
|
||||
link(href="{{ url_for('static_cloud', filename='assets/css/welcome.css') }}", rel="stylesheet")
|
||||
| {% endblock css %}
|
||||
|
||||
| {% block page_overlay %}
|
||||
#page-overlay.video
|
||||
@@ -19,9 +23,10 @@ meta(property="og:image", content="{{ url_for('static', filename='assets/img/bac
|
||||
|
||||
| {% block navigation_search %}{% endblock %}
|
||||
| {% block navigation_sections %}
|
||||
li
|
||||
a.navbar-item(href="#pricing")
|
||||
span Pricing
|
||||
li.nav-item
|
||||
a.nav-link(href="{{ url_for('main.main_blog') }}") Blog
|
||||
li.nav-item
|
||||
a.nav-link(href="#pricing") Pricing
|
||||
| {% endblock navigation_sections %}
|
||||
|
||||
| {% block navigation_user %}
|
||||
@@ -113,21 +118,21 @@ li.nav-item-sign-in
|
||||
|
||||
section.page-card-header
|
||||
a(href="{{ url_for('cloud.courses') }}")
|
||||
h2 Featured Training
|
||||
h2 Featured Content
|
||||
|
||||
.page-triplet-container.homepage
|
||||
.row
|
||||
.col-md-4
|
||||
.triplet-card(data-url="https://cloud.blender.org/p/toon-character-workflow/")
|
||||
.triplet-card(data-url="https://cloud.blender.org/p/minecraft-animation-workshop/")
|
||||
.triplet-card-thumbnail
|
||||
img(
|
||||
alt="Textures",
|
||||
src="{{ url_for('static', filename='assets/img/features/training_toon_character.jpg')}}")
|
||||
src="{{ url_for('static', filename='assets/img/features/training_minecraft_animation.jpg')}}")
|
||||
.triplet-card-info
|
||||
h3 Toon Character Workflow
|
||||
h3 Minecraft Animation
|
||||
p.
|
||||
Perfect for beginners, learn how to build a cartoon character from concept to finish.
|
||||
a.triplet-cta(href="https://cloud.blender.org/p/toon-character-workflow/")
|
||||
Learn how to make animations with this workshop by Dillon Gu.
|
||||
a.triplet-cta(href="https://cloud.blender.org/p/minecraft-animation-workshop/")
|
||||
| LEARN MORE
|
||||
|
||||
.col-md-4
|
||||
@@ -160,6 +165,7 @@ li.nav-item-sign-in
|
||||
.col-md-10.col-md-offset-1
|
||||
p.
|
||||
Other training:
|
||||
#[a(href="https://cloud.blender.org/p/toon-character-workflow/") Toon Character Workflow],
|
||||
#[a(href="https://cloud.blender.org/p/3d-printing/") Blender for 3D Printing],
|
||||
#[a(href="https://cloud.blender.org/p/game-asset-creation/") Game Asset Creation],
|
||||
#[a(href="https://cloud.blender.org/p/blenderella/") Character Modeling],
|
||||
@@ -211,35 +217,41 @@ li.nav-item-sign-in
|
||||
.page-triplet-container.homepage
|
||||
.row
|
||||
.col-md-4
|
||||
.triplet-card(data-url="https://cloud.blender.org/p/cosmos-laundromat/")
|
||||
.triplet-card(data-url="https://cloud.blender.org/p/hero/")
|
||||
.triplet-card-thumbnail
|
||||
img(
|
||||
alt="HDRI",
|
||||
src="{{ url_for('static', filename='assets/img/features/open_movies_cosmos.jpg')}}")
|
||||
alt="Hero",
|
||||
src="{{ url_for('static', filename='assets/img/features/open_movies_hero.jpg')}}")
|
||||
.triplet-card-info
|
||||
h3 Cosmos Laundromat
|
||||
a.triplet-cta(href="https://cloud.blender.org/p/cosmos-laundromat/")
|
||||
h3 Hero
|
||||
p.
|
||||
The first ever Grease Pencil open movie made with Blender 2.8
|
||||
a.triplet-cta(href="https://cloud.blender.org/p/hero/")
|
||||
| LEARN MORE
|
||||
|
||||
.col-md-4
|
||||
.triplet-card(data-url="https://cloud.blender.org/p/agent-327/")
|
||||
.triplet-card(data-url="https://cloud.blender.org/p/spring/")
|
||||
.triplet-card-thumbnail
|
||||
img(
|
||||
alt="Textures",
|
||||
src="{{ url_for('static', filename='assets/img/features/open_movies_agent_barbershop.jpg')}}")
|
||||
alt="Spring",
|
||||
src="{{ url_for('static', filename='assets/img/features/open_movies_spring.jpg')}}")
|
||||
.triplet-card-info
|
||||
h3 Agent 327
|
||||
a.triplet-cta(href="https://cloud.blender.org/p/agent-327/")
|
||||
h3 Spring
|
||||
p.
|
||||
A poetic fantasy film. #[br] A stunning visual journey.
|
||||
a.triplet-cta(href="https://cloud.blender.org/p/spring/")
|
||||
| LEARN MORE
|
||||
|
||||
.col-md-4
|
||||
.triplet-card(data-url="https://cloud.blender.org/p/caminandes-3/")
|
||||
.triplet-card-thumbnail
|
||||
img(
|
||||
alt="Characters",
|
||||
alt="Caminandes",
|
||||
src="{{ url_for('static', filename='assets/img/features/open_movies_caminandes_llamigos.jpg')}}")
|
||||
.triplet-card-info
|
||||
h3 Caminandes
|
||||
p.
|
||||
Follow the adventures of Koro through the Patagonian pampas.
|
||||
a.triplet-cta(href="https://cloud.blender.org/p/caminandes-3/")
|
||||
| LEARN MORE
|
||||
|
||||
@@ -251,8 +263,10 @@ li.nav-item-sign-in
|
||||
#[a(href="https://cloud.blender.org/p/big-buck-bunny/") Big Buck Bunny],
|
||||
#[a(href="https://cloud.blender.org/p/sintel/") Sintel],
|
||||
#[a(href="https://cloud.blender.org/p/tears-of-steel/") Tears of Steel],
|
||||
#[a(href="https://cloud.blender.org/p/cosmos-laundromat/") Cosmos Laundromat],
|
||||
#[a(href="https://cloud.blender.org/p/glass-half/") Glass Half],
|
||||
#[a(href="https://cloud.blender.org/p/dailydweebs/") The Daily Dweebs]
|
||||
#[a(href="https://cloud.blender.org/p/dailydweebs/") The Daily Dweebs],
|
||||
#[a(href="https://cloud.blender.org/p/agent-327/") Agent 327]
|
||||
and #[a(href="{{ url_for('cloud.open_projects') }}") more]
|
||||
|
||||
|
||||
@@ -344,7 +358,7 @@ li.nav-item-sign-in
|
||||
.pricing-display
|
||||
span.currency-sign €
|
||||
span.digit-int 9
|
||||
span.digit-dec ,90 / month
|
||||
span.digit-dec ,90 / month
|
||||
|
||||
.pricing-caption
|
||||
p $11.50 USD
|
||||
@@ -359,7 +373,7 @@ li.nav-item-sign-in
|
||||
.pricing-display
|
||||
span.currency-sign €
|
||||
span.digit-int 109
|
||||
span.digit-dec ,00 / year
|
||||
span.digit-dec ,00 / year
|
||||
|
||||
.pricing-caption
|
||||
p $119 USD
|
||||
@@ -369,12 +383,12 @@ li.nav-item-sign-in
|
||||
|
||||
.box.monthly
|
||||
a(href="{{ subscribe_url }}")
|
||||
h3 Quaterly
|
||||
h3 Quarterly
|
||||
|
||||
.pricing-display
|
||||
span.currency-sign €
|
||||
span.digit-int 28
|
||||
span.digit-dec ,50 / year
|
||||
span.digit-dec ,50 / 3 months
|
||||
|
||||
.pricing-caption
|
||||
p $32 USD
|
||||
|
7
static/assets/bootstrap/css/bootstrap.min.css
vendored
Normal file
7
static/assets/bootstrap/css/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
static/assets/bootstrap/css/bootstrap.min.css.map
Normal file
1
static/assets/bootstrap/css/bootstrap.min.css.map
Normal file
File diff suppressed because one or more lines are too long
7
static/assets/bootstrap/js/bootstrap.min.js
vendored
Normal file
7
static/assets/bootstrap/js/bootstrap.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
static/assets/bootstrap/js/bootstrap.min.js.map
Normal file
1
static/assets/bootstrap/js/bootstrap.min.js.map
Normal file
File diff suppressed because one or more lines are too long
43
static/assets/bootstrap/sass/_alert.sass
Normal file
43
static/assets/bootstrap/sass/_alert.sass
Normal file
@@ -0,0 +1,43 @@
|
||||
//
|
||||
// Base styles
|
||||
//
|
||||
|
||||
.alert
|
||||
position: relative
|
||||
padding: $alert-padding-y $alert-padding-x
|
||||
margin-bottom: $alert-margin-bottom
|
||||
border: $alert-border-width solid transparent
|
||||
|
||||
+border-radius($alert-border-radius)
|
||||
|
||||
// Headings for larger alerts
|
||||
.alert-heading
|
||||
// Specified to prevent conflicts of changing $headings-color
|
||||
color: inherit
|
||||
|
||||
// Provide class for links that match alerts
|
||||
.alert-link
|
||||
font-weight: $alert-link-font-weight
|
||||
|
||||
// Dismissible alerts
|
||||
//
|
||||
// Expand the right padding and account for the close button's positioning.
|
||||
|
||||
.alert-dismissible
|
||||
padding-right: $close-font-size + $alert-padding-x * 2
|
||||
|
||||
// Adjust close link position
|
||||
.close
|
||||
position: absolute
|
||||
top: 0
|
||||
right: 0
|
||||
padding: $alert-padding-y $alert-padding-x
|
||||
color: inherit
|
||||
|
||||
// Alternate styles
|
||||
//
|
||||
// Generate contextual modifier classes for colorizing the alert.
|
||||
|
||||
@each $color, $value in $theme-colors
|
||||
.alert-#{$color}
|
||||
+alert-variant(theme-color-level($color, $alert-bg-level), theme-color-level($color, $alert-border-level), theme-color-level($color, $alert-color-level))
|
43
static/assets/bootstrap/sass/_badge.sass
Normal file
43
static/assets/bootstrap/sass/_badge.sass
Normal file
@@ -0,0 +1,43 @@
|
||||
// Base class
|
||||
//
|
||||
// Requires one of the contextual, color modifier classes for `color` and
|
||||
// `background-color`.
|
||||
|
||||
.badge
|
||||
display: inline-block
|
||||
padding: $badge-padding-y $badge-padding-x
|
||||
font-size: $badge-font-size
|
||||
font-weight: $badge-font-weight
|
||||
line-height: 1
|
||||
text-align: center
|
||||
white-space: nowrap
|
||||
vertical-align: baseline
|
||||
|
||||
+border-radius($badge-border-radius)
|
||||
|
||||
// Empty badges collapse automatically
|
||||
&:empty
|
||||
display: none
|
||||
|
||||
// Quick fix for badges in buttons
|
||||
.btn .badge
|
||||
position: relative
|
||||
top: -1px
|
||||
|
||||
// Pill badges
|
||||
//
|
||||
// Make them extra rounded with a modifier to replace v3's badges.
|
||||
|
||||
.badge-pill
|
||||
padding-right: $badge-pill-padding-x
|
||||
padding-left: $badge-pill-padding-x
|
||||
|
||||
+border-radius($badge-pill-border-radius)
|
||||
|
||||
// Colors
|
||||
//
|
||||
// Contextual variations (linked badges get darker on :hover).
|
||||
|
||||
@each $color, $value in $theme-colors
|
||||
.badge-#{$color}
|
||||
+badge-variant($value)
|
38
static/assets/bootstrap/sass/_breadcrumb.sass
Normal file
38
static/assets/bootstrap/sass/_breadcrumb.sass
Normal file
@@ -0,0 +1,38 @@
|
||||
.breadcrumb
|
||||
display: flex
|
||||
flex-wrap: wrap
|
||||
padding: $breadcrumb-padding-y $breadcrumb-padding-x
|
||||
margin-bottom: $breadcrumb-margin-bottom
|
||||
list-style: none
|
||||
background-color: $breadcrumb-bg
|
||||
|
||||
+border-radius($breadcrumb-border-radius)
|
||||
|
||||
.breadcrumb-item
|
||||
// The separator between breadcrumbs (by default, a forward-slash: "/")
|
||||
+ .breadcrumb-item
|
||||
padding-left: $breadcrumb-item-padding
|
||||
|
||||
&::before
|
||||
display: inline-block
|
||||
|
||||
// Suppress underlining of the separator in modern browsers
|
||||
padding-right: $breadcrumb-item-padding
|
||||
color: $breadcrumb-divider-color
|
||||
content: $breadcrumb-divider
|
||||
|
||||
// IE9-11 hack to properly handle hyperlink underlines for breadcrumbs built
|
||||
// without `<ul>`s. The `::before` pseudo-element generates an element
|
||||
// *within* the .breadcrumb-item and thereby inherits the `text-decoration`.
|
||||
//
|
||||
// To trick IE into suppressing the underline, we give the pseudo-element an
|
||||
// underline and then immediately remove it.
|
||||
+ .breadcrumb-item:hover::before
|
||||
text-decoration: underline
|
||||
|
||||
// stylelint-disable-next-line no-duplicate-selectors
|
||||
+ .breadcrumb-item:hover::before
|
||||
text-decoration: none
|
||||
|
||||
&.active
|
||||
color: $breadcrumb-active-color
|
151
static/assets/bootstrap/sass/_button-group.sass
Normal file
151
static/assets/bootstrap/sass/_button-group.sass
Normal file
@@ -0,0 +1,151 @@
|
||||
// stylelint-disable selector-no-qualifying-type
|
||||
|
||||
// Make the div behave like a button
|
||||
.btn-group,
|
||||
.btn-group-vertical
|
||||
position: relative
|
||||
display: inline-flex
|
||||
vertical-align: middle
|
||||
|
||||
// match .btn alignment given font-size hack above
|
||||
|
||||
> .btn
|
||||
position: relative
|
||||
flex: 0 1 auto
|
||||
|
||||
// Bring the hover, focused, and "active" buttons to the front to overlay
|
||||
// the borders properly
|
||||
+hover
|
||||
z-index: 1
|
||||
|
||||
|
||||
&:focus,
|
||||
&:active,
|
||||
&.active
|
||||
z-index: 1
|
||||
|
||||
// Prevent double borders when buttons are next to each other
|
||||
.btn + .btn,
|
||||
.btn + .btn-group,
|
||||
.btn-group + .btn,
|
||||
.btn-group + .btn-group
|
||||
margin-left: -$btn-border-width
|
||||
|
||||
// Optional: Group multiple button groups together for a toolbar
|
||||
.btn-toolbar
|
||||
display: flex
|
||||
flex-wrap: wrap
|
||||
justify-content: flex-start
|
||||
|
||||
.input-group
|
||||
width: auto
|
||||
|
||||
.btn-group
|
||||
> .btn:first-child
|
||||
margin-left: 0
|
||||
|
||||
// Reset rounded corners
|
||||
> .btn:not(:last-child):not(.dropdown-toggle),
|
||||
> .btn-group:not(:last-child) > .btn
|
||||
+border-right-radius(0)
|
||||
|
||||
> .btn:not(:first-child),
|
||||
> .btn-group:not(:first-child) > .btn
|
||||
+border-left-radius(0)
|
||||
|
||||
// Sizing
|
||||
//
|
||||
// Remix the default button sizing classes into new ones for easier manipulation.
|
||||
|
||||
.btn-group-sm > .btn
|
||||
@extend .btn-sm
|
||||
|
||||
.btn-group-lg > .btn
|
||||
@extend .btn-lg
|
||||
|
||||
//
|
||||
// Split button dropdowns
|
||||
//
|
||||
|
||||
.dropdown-toggle-split
|
||||
padding-right: $btn-padding-x * 0.75
|
||||
padding-left: $btn-padding-x * 0.75
|
||||
|
||||
&::after,
|
||||
.dropup &::after,
|
||||
.dropright &::after
|
||||
margin-left: 0
|
||||
|
||||
.dropleft &::before
|
||||
margin-right: 0
|
||||
|
||||
.btn-sm + .dropdown-toggle-split
|
||||
padding-right: $btn-padding-x-sm * 0.75
|
||||
padding-left: $btn-padding-x-sm * 0.75
|
||||
|
||||
.btn-lg + .dropdown-toggle-split
|
||||
padding-right: $btn-padding-x-lg * 0.75
|
||||
padding-left: $btn-padding-x-lg * 0.75
|
||||
|
||||
// The clickable button for toggling the menu
|
||||
// Set the same inset shadow as the :active state
|
||||
.btn-group.show .dropdown-toggle
|
||||
+box-shadow($btn-active-box-shadow)
|
||||
|
||||
// Show no shadow for `.btn-link` since it has no other button styles.
|
||||
&.btn-link
|
||||
+box-shadow(none)
|
||||
|
||||
//
|
||||
// Vertical button groups
|
||||
//
|
||||
|
||||
.btn-group-vertical
|
||||
flex-direction: column
|
||||
align-items: flex-start
|
||||
justify-content: center
|
||||
|
||||
.btn,
|
||||
.btn-group
|
||||
width: 100%
|
||||
|
||||
> .btn + .btn,
|
||||
> .btn + .btn-group,
|
||||
> .btn-group + .btn,
|
||||
> .btn-group + .btn-group
|
||||
margin-top: -$btn-border-width
|
||||
margin-left: 0
|
||||
|
||||
// Reset rounded corners
|
||||
> .btn:not(:last-child):not(.dropdown-toggle),
|
||||
> .btn-group:not(:last-child) > .btn
|
||||
+border-bottom-radius(0)
|
||||
|
||||
> .btn:not(:first-child),
|
||||
> .btn-group:not(:first-child) > .btn
|
||||
+border-top-radius(0)
|
||||
|
||||
// Checkbox and radio options
|
||||
//
|
||||
// In order to support the browser's form validation feedback, powered by the
|
||||
// `required` attribute, we have to "hide" the inputs via `clip`. We cannot use
|
||||
// `display: none;` or `visibility: hidden;` as that also hides the popover.
|
||||
// Simply visually hiding the inputs via `opacity` would leave them clickable in
|
||||
// certain cases which is prevented by using `clip` and `pointer-events`.
|
||||
// This way, we ensure a DOM element is visible to position the popover from.
|
||||
//
|
||||
// See https://github.com/twbs/bootstrap/pull/12794 and
|
||||
// https://github.com/twbs/bootstrap/pull/14559 for more information.
|
||||
|
||||
.btn-group-toggle
|
||||
> .btn,
|
||||
> .btn-group > .btn
|
||||
margin-bottom: 0
|
||||
|
||||
// Override default `<label>` value
|
||||
|
||||
input[type="radio"],
|
||||
input[type="checkbox"]
|
||||
position: absolute
|
||||
clip: rect(0, 0, 0, 0)
|
||||
pointer-events: none
|
123
static/assets/bootstrap/sass/_buttons.sass
Normal file
123
static/assets/bootstrap/sass/_buttons.sass
Normal file
@@ -0,0 +1,123 @@
|
||||
// stylelint-disable selector-no-qualifying-type
|
||||
|
||||
//
|
||||
// Base styles
|
||||
//
|
||||
|
||||
.btn
|
||||
display: inline-block
|
||||
font-weight: $btn-font-weight
|
||||
text-align: center
|
||||
white-space: nowrap
|
||||
vertical-align: middle
|
||||
user-select: none
|
||||
border: $btn-border-width solid transparent
|
||||
|
||||
+button-size($btn-padding-y, $btn-padding-x, $font-size-base, $btn-line-height, $btn-border-radius)
|
||||
+transition($btn-transition)
|
||||
|
||||
// Share hover and focus styles
|
||||
+hover-focus
|
||||
text-decoration: none
|
||||
|
||||
|
||||
&:focus,
|
||||
&.focus
|
||||
outline: 0
|
||||
box-shadow: $btn-focus-box-shadow
|
||||
|
||||
// Disabled comes first so active can properly restyle
|
||||
&.disabled,
|
||||
&:disabled
|
||||
opacity: $btn-disabled-opacity
|
||||
|
||||
+box-shadow(none)
|
||||
|
||||
// Opinionated: add "hand" cursor to non-disabled .btn elements
|
||||
&:not(:disabled):not(.disabled)
|
||||
cursor: pointer
|
||||
|
||||
&:not(:disabled):not(.disabled):active,
|
||||
&:not(:disabled):not(.disabled).active
|
||||
background-image: none
|
||||
|
||||
+box-shadow($btn-active-box-shadow)
|
||||
|
||||
&:focus
|
||||
+box-shadow($btn-focus-box-shadow, $btn-active-box-shadow)
|
||||
|
||||
// Future-proof disabling of clicks on `<a>` elements
|
||||
a.btn.disabled,
|
||||
fieldset:disabled a.btn
|
||||
pointer-events: none
|
||||
|
||||
//
|
||||
// Alternate buttons
|
||||
//
|
||||
|
||||
@each $color, $value in $theme-colors
|
||||
.btn-#{$color}
|
||||
+button-variant($value, $value)
|
||||
|
||||
@each $color, $value in $theme-colors
|
||||
.btn-outline-#{$color}
|
||||
+button-outline-variant($value)
|
||||
|
||||
//
|
||||
// Link buttons
|
||||
//
|
||||
|
||||
// Make a button look and behave like a link
|
||||
.btn-link
|
||||
font-weight: $font-weight-normal
|
||||
color: $link-color
|
||||
background-color: transparent
|
||||
|
||||
+hover
|
||||
color: $link-hover-color
|
||||
text-decoration: $link-hover-decoration
|
||||
background-color: transparent
|
||||
border-color: transparent
|
||||
|
||||
|
||||
&:focus,
|
||||
&.focus
|
||||
text-decoration: $link-hover-decoration
|
||||
border-color: transparent
|
||||
box-shadow: none
|
||||
|
||||
&:disabled,
|
||||
&.disabled
|
||||
color: $btn-link-disabled-color
|
||||
pointer-events: none
|
||||
|
||||
// No need for an active state here
|
||||
|
||||
//
|
||||
// Button Sizes
|
||||
//
|
||||
|
||||
.btn-lg
|
||||
+button-size($btn-padding-y-lg, $btn-padding-x-lg, $font-size-lg, $btn-line-height-lg, $btn-border-radius-lg)
|
||||
|
||||
.btn-sm
|
||||
+button-size($btn-padding-y-sm, $btn-padding-x-sm, $font-size-sm, $btn-line-height-sm, $btn-border-radius-sm)
|
||||
|
||||
//
|
||||
// Block button
|
||||
//
|
||||
|
||||
.btn-block
|
||||
display: block
|
||||
width: 100%
|
||||
|
||||
// Vertically space out multiple block buttons
|
||||
+ .btn-block
|
||||
margin-top: $btn-block-spacing-y
|
||||
|
||||
// Specificity overrides
|
||||
input[type="submit"],
|
||||
input[type="reset"],
|
||||
input[type="button"]
|
||||
&.btn-block
|
||||
width: 100%
|
261
static/assets/bootstrap/sass/_card.sass
Normal file
261
static/assets/bootstrap/sass/_card.sass
Normal file
@@ -0,0 +1,261 @@
|
||||
//
|
||||
// Base styles
|
||||
//
|
||||
|
||||
.card
|
||||
position: relative
|
||||
display: flex
|
||||
flex-direction: column
|
||||
min-width: 0
|
||||
word-wrap: break-word
|
||||
background-color: $card-bg
|
||||
background-clip: border-box
|
||||
border: $card-border-width solid $card-border-color
|
||||
|
||||
+border-radius($card-border-radius)
|
||||
|
||||
> hr
|
||||
margin-right: 0
|
||||
margin-left: 0
|
||||
|
||||
> .list-group:first-child
|
||||
.list-group-item:first-child
|
||||
+border-top-radius($card-border-radius)
|
||||
|
||||
> .list-group:last-child
|
||||
.list-group-item:last-child
|
||||
+border-bottom-radius($card-border-radius)
|
||||
|
||||
.card-body
|
||||
// Enable `flex-grow: 1` for decks and groups so that card blocks take up
|
||||
// as much space as possible, ensuring footers are aligned to the bottom.
|
||||
flex: 1 1 auto
|
||||
padding: $card-spacer-x
|
||||
|
||||
.card-title
|
||||
margin-bottom: $card-spacer-y
|
||||
|
||||
.card-subtitle
|
||||
margin-top: -($card-spacer-y / 2)
|
||||
margin-bottom: 0
|
||||
|
||||
.card-text:last-child
|
||||
margin-bottom: 0
|
||||
|
||||
.card-link
|
||||
+hover
|
||||
text-decoration: none
|
||||
|
||||
|
||||
+ .card-link
|
||||
margin-left: $card-spacer-x
|
||||
|
||||
//
|
||||
// Optional textual caps
|
||||
//
|
||||
|
||||
.card-header
|
||||
padding: $card-spacer-y $card-spacer-x
|
||||
margin-bottom: 0
|
||||
|
||||
// Removes the default margin-bottom of <hN>
|
||||
background-color: $card-cap-bg
|
||||
border-bottom: $card-border-width solid $card-border-color
|
||||
|
||||
&:first-child
|
||||
+border-radius($card-inner-border-radius $card-inner-border-radius 0 0)
|
||||
|
||||
+ .list-group
|
||||
.list-group-item:first-child
|
||||
border-top: 0
|
||||
|
||||
.card-footer
|
||||
padding: $card-spacer-y $card-spacer-x
|
||||
background-color: $card-cap-bg
|
||||
border-top: $card-border-width solid $card-border-color
|
||||
|
||||
&:last-child
|
||||
+border-radius(0 0 $card-inner-border-radius $card-inner-border-radius)
|
||||
|
||||
//
|
||||
// Header navs
|
||||
//
|
||||
|
||||
.card-header-tabs
|
||||
margin-right: -($card-spacer-x / 2)
|
||||
margin-bottom: -$card-spacer-y
|
||||
margin-left: -($card-spacer-x / 2)
|
||||
border-bottom: 0
|
||||
|
||||
.card-header-pills
|
||||
margin-right: -($card-spacer-x / 2)
|
||||
margin-left: -($card-spacer-x / 2)
|
||||
|
||||
// Card image
|
||||
.card-img-overlay
|
||||
position: absolute
|
||||
top: 0
|
||||
right: 0
|
||||
bottom: 0
|
||||
left: 0
|
||||
padding: $card-img-overlay-padding
|
||||
|
||||
.card-img
|
||||
width: 100%
|
||||
|
||||
// Required because we use flexbox and this inherently applies align-self: stretch
|
||||
+border-radius($card-inner-border-radius)
|
||||
|
||||
// Card image caps
|
||||
.card-img-top
|
||||
width: 100%
|
||||
|
||||
// Required because we use flexbox and this inherently applies align-self: stretch
|
||||
+border-top-radius($card-inner-border-radius)
|
||||
|
||||
.card-img-bottom
|
||||
width: 100%
|
||||
|
||||
// Required because we use flexbox and this inherently applies align-self: stretch
|
||||
+border-bottom-radius($card-inner-border-radius)
|
||||
|
||||
// Card deck
|
||||
|
||||
.card-deck
|
||||
display: flex
|
||||
flex-direction: column
|
||||
|
||||
.card
|
||||
margin-bottom: $card-deck-margin
|
||||
|
||||
+media-breakpoint-up(sm)
|
||||
flex-flow: row wrap
|
||||
margin-right: -$card-deck-margin
|
||||
margin-left: -$card-deck-margin
|
||||
|
||||
.card
|
||||
display: flex
|
||||
|
||||
// Flexbugs #4: https://github.com/philipwalton/flexbugs#flexbug-4
|
||||
flex: 1 0 0%
|
||||
flex-direction: column
|
||||
margin-right: $card-deck-margin
|
||||
margin-bottom: 0
|
||||
|
||||
// Override the default
|
||||
margin-left: $card-deck-margin
|
||||
|
||||
//
|
||||
// Card groups
|
||||
//
|
||||
|
||||
.card-group
|
||||
display: flex
|
||||
flex-direction: column
|
||||
|
||||
// The child selector allows nested `.card` within `.card-group`
|
||||
// to display properly.
|
||||
> .card
|
||||
margin-bottom: $card-group-margin
|
||||
|
||||
+media-breakpoint-up(sm)
|
||||
flex-flow: row wrap
|
||||
|
||||
// The child selector allows nested `.card` within `.card-group`
|
||||
// to display properly.
|
||||
> .card
|
||||
// Flexbugs #4: https://github.com/philipwalton/flexbugs#flexbug-4
|
||||
flex: 1 0 0%
|
||||
margin-bottom: 0
|
||||
|
||||
+ .card
|
||||
margin-left: 0
|
||||
border-left: 0
|
||||
|
||||
// Handle rounded corners
|
||||
@if $enable-rounded
|
||||
&:first-child
|
||||
+border-right-radius(0)
|
||||
|
||||
.card-img-top,
|
||||
.card-header
|
||||
border-top-right-radius: 0
|
||||
|
||||
.card-img-bottom,
|
||||
.card-footer
|
||||
border-bottom-right-radius: 0
|
||||
|
||||
&:last-child
|
||||
+border-left-radius(0)
|
||||
|
||||
.card-img-top,
|
||||
.card-header
|
||||
border-top-left-radius: 0
|
||||
|
||||
.card-img-bottom,
|
||||
.card-footer
|
||||
border-bottom-left-radius: 0
|
||||
|
||||
&:only-child
|
||||
+border-radius($card-border-radius)
|
||||
|
||||
.card-img-top,
|
||||
.card-header
|
||||
+border-top-radius($card-border-radius)
|
||||
|
||||
.card-img-bottom,
|
||||
.card-footer
|
||||
+border-bottom-radius($card-border-radius)
|
||||
|
||||
&:not(:first-child):not(:last-child):not(:only-child)
|
||||
+border-radius(0)
|
||||
|
||||
.card-img-top,
|
||||
.card-img-bottom,
|
||||
.card-header,
|
||||
.card-footer
|
||||
+border-radius(0)
|
||||
|
||||
//
|
||||
// Columns
|
||||
//
|
||||
|
||||
.card-columns
|
||||
.card
|
||||
margin-bottom: $card-columns-margin
|
||||
|
||||
+media-breakpoint-up(sm)
|
||||
column-count: $card-columns-count
|
||||
column-gap: $card-columns-gap
|
||||
orphans: 1
|
||||
widows: 1
|
||||
|
||||
.card
|
||||
display: inline-block
|
||||
|
||||
// Don't let them vertically span multiple columns
|
||||
width: 100%
|
||||
|
||||
// Don't let their width change
|
||||
|
||||
//
|
||||
// Accordion
|
||||
//
|
||||
|
||||
.accordion
|
||||
.card:not(:first-of-type):not(:last-of-type)
|
||||
border-bottom: 0
|
||||
border-radius: 0
|
||||
|
||||
.card:not(:first-of-type)
|
||||
.card-header:first-child
|
||||
border-radius: 0
|
||||
|
||||
.card:first-of-type
|
||||
border-bottom: 0
|
||||
border-bottom-right-radius: 0
|
||||
border-bottom-left-radius: 0
|
||||
|
||||
.card:last-of-type
|
||||
border-top-left-radius: 0
|
||||
border-top-right-radius: 0
|
218
static/assets/bootstrap/sass/_carousel.sass
Normal file
218
static/assets/bootstrap/sass/_carousel.sass
Normal file
@@ -0,0 +1,218 @@
|
||||
// Notes on the classes:
|
||||
//
|
||||
// 1. The .carousel-item-left and .carousel-item-right is used to indicate where
|
||||
// the active slide is heading.
|
||||
// 2. .active.carousel-item is the current slide.
|
||||
// 3. .active.carousel-item-left and .active.carousel-item-right is the current
|
||||
// slide in its in-transition state. Only one of these occurs at a time.
|
||||
// 4. .carousel-item-next.carousel-item-left and .carousel-item-prev.carousel-item-right
|
||||
// is the upcoming slide in transition.
|
||||
|
||||
.carousel
|
||||
position: relative
|
||||
|
||||
.carousel-inner
|
||||
position: relative
|
||||
width: 100%
|
||||
overflow: hidden
|
||||
|
||||
.carousel-item
|
||||
position: relative
|
||||
display: none
|
||||
align-items: center
|
||||
width: 100%
|
||||
backface-visibility: hidden
|
||||
perspective: 1000px
|
||||
|
||||
.carousel-item.active,
|
||||
.carousel-item-next,
|
||||
.carousel-item-prev
|
||||
display: block
|
||||
|
||||
+transition($carousel-transition)
|
||||
|
||||
.carousel-item-next,
|
||||
.carousel-item-prev
|
||||
position: absolute
|
||||
top: 0
|
||||
|
||||
.carousel-item-next.carousel-item-left,
|
||||
.carousel-item-prev.carousel-item-right
|
||||
transform: translateX(0)
|
||||
|
||||
@supports (transform-style: preserve-3d)
|
||||
transform: translate3d(0, 0, 0)
|
||||
|
||||
.carousel-item-next,
|
||||
.active.carousel-item-right
|
||||
transform: translateX(100%)
|
||||
|
||||
@supports (transform-style: preserve-3d)
|
||||
transform: translate3d(100%, 0, 0)
|
||||
|
||||
.carousel-item-prev,
|
||||
.active.carousel-item-left
|
||||
transform: translateX(-100%)
|
||||
|
||||
@supports (transform-style: preserve-3d)
|
||||
transform: translate3d(-100%, 0, 0)
|
||||
|
||||
//
|
||||
// Alternate transitions
|
||||
//
|
||||
|
||||
.carousel-fade
|
||||
.carousel-item
|
||||
opacity: 0
|
||||
transition-duration: .6s
|
||||
transition-property: opacity
|
||||
|
||||
.carousel-item.active,
|
||||
.carousel-item-next.carousel-item-left,
|
||||
.carousel-item-prev.carousel-item-right
|
||||
opacity: 1
|
||||
|
||||
.active.carousel-item-left,
|
||||
.active.carousel-item-right
|
||||
opacity: 0
|
||||
|
||||
.carousel-item-next,
|
||||
.carousel-item-prev,
|
||||
.carousel-item.active,
|
||||
.active.carousel-item-left,
|
||||
.active.carousel-item-prev
|
||||
transform: translateX(0)
|
||||
|
||||
@supports (transform-style: preserve-3d)
|
||||
transform: translate3d(0, 0, 0)
|
||||
|
||||
//
|
||||
// Left/right controls for nav
|
||||
//
|
||||
|
||||
.carousel-control-prev,
|
||||
.carousel-control-next
|
||||
position: absolute
|
||||
top: 0
|
||||
bottom: 0
|
||||
|
||||
// Use flex for alignment (1-3)
|
||||
display: flex
|
||||
|
||||
// 1. allow flex styles
|
||||
align-items: center
|
||||
|
||||
// 2. vertically center contents
|
||||
justify-content: center
|
||||
|
||||
// 3. horizontally center contents
|
||||
width: $carousel-control-width
|
||||
color: $carousel-control-color
|
||||
text-align: center
|
||||
opacity: $carousel-control-opacity
|
||||
|
||||
// We can't have a transition here because WebKit cancels the carousel
|
||||
// animation if you trip this while in the middle of another animation.
|
||||
|
||||
// Hover/focus state
|
||||
+hover-focus
|
||||
color: $carousel-control-color
|
||||
text-decoration: none
|
||||
outline: 0
|
||||
opacity: .9
|
||||
|
||||
.carousel-control-prev
|
||||
left: 0
|
||||
|
||||
@if $enable-gradients
|
||||
background: linear-gradient(90deg, rgba($black, 0.25), rgba($black, 0.001))
|
||||
|
||||
.carousel-control-next
|
||||
right: 0
|
||||
|
||||
@if $enable-gradients
|
||||
background: linear-gradient(270deg, rgba($black, 0.25), rgba($black, 0.001))
|
||||
|
||||
// Icons for within
|
||||
.carousel-control-prev-icon,
|
||||
.carousel-control-next-icon
|
||||
display: inline-block
|
||||
width: $carousel-control-icon-width
|
||||
height: $carousel-control-icon-width
|
||||
background: transparent no-repeat center center
|
||||
background-size: 100% 100%
|
||||
|
||||
.carousel-control-prev-icon
|
||||
background-image: $carousel-control-prev-icon-bg
|
||||
|
||||
.carousel-control-next-icon
|
||||
background-image: $carousel-control-next-icon-bg
|
||||
|
||||
// Optional indicator pips
|
||||
//
|
||||
// Add an ordered list with the following class and add a list item for each
|
||||
// slide your carousel holds.
|
||||
|
||||
.carousel-indicators
|
||||
position: absolute
|
||||
right: 0
|
||||
bottom: 10px
|
||||
left: 0
|
||||
z-index: 15
|
||||
display: flex
|
||||
justify-content: center
|
||||
padding-left: 0
|
||||
|
||||
// override <ol> default
|
||||
// Use the .carousel-control's width as margin so we don't overlay those
|
||||
margin-right: $carousel-control-width
|
||||
margin-left: $carousel-control-width
|
||||
list-style: none
|
||||
|
||||
li
|
||||
position: relative
|
||||
flex: 0 1 auto
|
||||
width: $carousel-indicator-width
|
||||
height: $carousel-indicator-height
|
||||
margin-right: $carousel-indicator-spacer
|
||||
margin-left: $carousel-indicator-spacer
|
||||
text-indent: -999px
|
||||
cursor: pointer
|
||||
background-color: rgba($carousel-indicator-active-bg, 0.5)
|
||||
|
||||
// Use pseudo classes to increase the hit area by 10px on top and bottom.
|
||||
&::before
|
||||
position: absolute
|
||||
top: -10px
|
||||
left: 0
|
||||
display: inline-block
|
||||
width: 100%
|
||||
height: 10px
|
||||
content: ""
|
||||
|
||||
&::after
|
||||
position: absolute
|
||||
bottom: -10px
|
||||
left: 0
|
||||
display: inline-block
|
||||
width: 100%
|
||||
height: 10px
|
||||
content: ""
|
||||
|
||||
.active
|
||||
background-color: $carousel-indicator-active-bg
|
||||
|
||||
// Optional captions
|
||||
//
|
||||
//
|
||||
|
||||
.carousel-caption
|
||||
position: absolute
|
||||
right: (100% - $carousel-caption-width) / 2
|
||||
bottom: 20px
|
||||
left: (100% - $carousel-caption-width) / 2
|
||||
z-index: 10
|
||||
padding-top: 20px
|
||||
padding-bottom: 20px
|
||||
color: $carousel-caption-color
|
||||
text-align: center
|
32
static/assets/bootstrap/sass/_close.sass
Normal file
32
static/assets/bootstrap/sass/_close.sass
Normal file
@@ -0,0 +1,32 @@
|
||||
.close
|
||||
float: right
|
||||
font-size: $close-font-size
|
||||
font-weight: $close-font-weight
|
||||
line-height: 1
|
||||
color: $close-color
|
||||
text-shadow: $close-text-shadow
|
||||
opacity: .5
|
||||
|
||||
&:not(:disabled):not(.disabled)
|
||||
+hover-focus
|
||||
color: $close-color
|
||||
text-decoration: none
|
||||
opacity: .75
|
||||
|
||||
|
||||
// Opinionated: add "hand" cursor to non-disabled .close elements
|
||||
cursor: pointer
|
||||
|
||||
// Additional properties for button version
|
||||
// iOS requires the button element instead of an anchor tag.
|
||||
// If you want the anchor version, it requires `href="#"`.
|
||||
// See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile
|
||||
|
||||
// stylelint-disable property-no-vendor-prefix, selector-no-qualifying-type
|
||||
button.close
|
||||
padding: 0
|
||||
background-color: transparent
|
||||
border: 0
|
||||
-webkit-appearance: none
|
||||
|
||||
// stylelint-enable
|
43
static/assets/bootstrap/sass/_code.sass
Normal file
43
static/assets/bootstrap/sass/_code.sass
Normal file
@@ -0,0 +1,43 @@
|
||||
// Inline code
|
||||
code
|
||||
font-size: $code-font-size
|
||||
color: $code-color
|
||||
word-break: break-word
|
||||
|
||||
// Streamline the style when inside anchors to avoid broken underline and more
|
||||
a > &
|
||||
color: inherit
|
||||
|
||||
// User input typically entered via keyboard
|
||||
kbd
|
||||
padding: $kbd-padding-y $kbd-padding-x
|
||||
font-size: $kbd-font-size
|
||||
color: $kbd-color
|
||||
background-color: $kbd-bg
|
||||
|
||||
+border-radius($border-radius-sm)
|
||||
+box-shadow($kbd-box-shadow)
|
||||
|
||||
kbd
|
||||
padding: 0
|
||||
font-size: 100%
|
||||
font-weight: $nested-kbd-font-weight
|
||||
|
||||
+box-shadow(none)
|
||||
|
||||
// Blocks of code
|
||||
pre
|
||||
display: block
|
||||
font-size: $code-font-size
|
||||
color: $pre-color
|
||||
|
||||
// Account for some code outputs that place code tags in pre tags
|
||||
code
|
||||
font-size: inherit
|
||||
color: inherit
|
||||
word-break: normal
|
||||
|
||||
// Enable scrollable blocks of code
|
||||
.pre-scrollable
|
||||
max-height: $pre-scrollable-max-height
|
||||
overflow-y: scroll
|
416
static/assets/bootstrap/sass/_custom-forms.sass
Normal file
416
static/assets/bootstrap/sass/_custom-forms.sass
Normal file
@@ -0,0 +1,416 @@
|
||||
// Embedded icons from Open Iconic.
|
||||
// Released under MIT and copyright 2014 Waybury.
|
||||
// https://useiconic.com/open
|
||||
|
||||
// Checkboxes and radios
|
||||
//
|
||||
// Base class takes care of all the key behavioral aspects.
|
||||
|
||||
.custom-control
|
||||
position: relative
|
||||
display: block
|
||||
min-height: 1rem * $line-height-base
|
||||
padding-left: $custom-control-gutter
|
||||
|
||||
.custom-control-inline
|
||||
display: inline-flex
|
||||
margin-right: $custom-control-spacer-x
|
||||
|
||||
.custom-control-input
|
||||
position: absolute
|
||||
z-index: -1
|
||||
|
||||
// Put the input behind the label so it doesn't overlay text
|
||||
opacity: 0
|
||||
|
||||
&:checked ~ .custom-control-label::before
|
||||
color: $custom-control-indicator-checked-color
|
||||
|
||||
+gradient-bg($custom-control-indicator-checked-bg)
|
||||
+box-shadow($custom-control-indicator-checked-box-shadow)
|
||||
|
||||
&:focus ~ .custom-control-label::before
|
||||
// the mixin is not used here to make sure there is feedback
|
||||
box-shadow: $custom-control-indicator-focus-box-shadow
|
||||
|
||||
&:active ~ .custom-control-label::before
|
||||
color: $custom-control-indicator-active-color
|
||||
background-color: $custom-control-indicator-active-bg
|
||||
|
||||
+box-shadow($custom-control-indicator-active-box-shadow)
|
||||
|
||||
&:disabled
|
||||
~ .custom-control-label
|
||||
color: $custom-control-label-disabled-color
|
||||
|
||||
&::before
|
||||
background-color: $custom-control-indicator-disabled-bg
|
||||
|
||||
// Custom control indicators
|
||||
//
|
||||
// Build the custom controls out of pseudo-elements.
|
||||
|
||||
.custom-control-label
|
||||
position: relative
|
||||
margin-bottom: 0
|
||||
|
||||
// Background-color and (when enabled) gradient
|
||||
&::before
|
||||
position: absolute
|
||||
top: ($line-height-base - $custom-control-indicator-size) / 2
|
||||
left: -$custom-control-gutter
|
||||
display: block
|
||||
width: $custom-control-indicator-size
|
||||
height: $custom-control-indicator-size
|
||||
pointer-events: none
|
||||
content: ""
|
||||
user-select: none
|
||||
background-color: $custom-control-indicator-bg
|
||||
|
||||
+box-shadow($custom-control-indicator-box-shadow)
|
||||
|
||||
// Foreground (icon)
|
||||
&::after
|
||||
position: absolute
|
||||
top: ($line-height-base - $custom-control-indicator-size) / 2
|
||||
left: -$custom-control-gutter
|
||||
display: block
|
||||
width: $custom-control-indicator-size
|
||||
height: $custom-control-indicator-size
|
||||
content: ""
|
||||
background-repeat: no-repeat
|
||||
background-position: center center
|
||||
background-size: $custom-control-indicator-bg-size
|
||||
|
||||
// Checkboxes
|
||||
//
|
||||
// Tweak just a few things for checkboxes.
|
||||
|
||||
.custom-checkbox
|
||||
.custom-control-label::before
|
||||
+border-radius($custom-checkbox-indicator-border-radius)
|
||||
|
||||
.custom-control-input:checked ~ .custom-control-label
|
||||
&::before
|
||||
+gradient-bg($custom-control-indicator-checked-bg)
|
||||
|
||||
&::after
|
||||
background-image: $custom-checkbox-indicator-icon-checked
|
||||
|
||||
.custom-control-input:indeterminate ~ .custom-control-label
|
||||
&::before
|
||||
+gradient-bg($custom-checkbox-indicator-indeterminate-bg)
|
||||
+box-shadow($custom-checkbox-indicator-indeterminate-box-shadow)
|
||||
|
||||
&::after
|
||||
background-image: $custom-checkbox-indicator-icon-indeterminate
|
||||
|
||||
.custom-control-input:disabled
|
||||
&:checked ~ .custom-control-label::before
|
||||
background-color: $custom-control-indicator-checked-disabled-bg
|
||||
|
||||
&:indeterminate ~ .custom-control-label::before
|
||||
background-color: $custom-control-indicator-checked-disabled-bg
|
||||
|
||||
// Radios
|
||||
//
|
||||
// Tweak just a few things for radios.
|
||||
|
||||
.custom-radio
|
||||
.custom-control-label::before
|
||||
border-radius: $custom-radio-indicator-border-radius
|
||||
|
||||
.custom-control-input:checked ~ .custom-control-label
|
||||
&::before
|
||||
+gradient-bg($custom-control-indicator-checked-bg)
|
||||
|
||||
&::after
|
||||
background-image: $custom-radio-indicator-icon-checked
|
||||
|
||||
.custom-control-input:disabled
|
||||
&:checked ~ .custom-control-label::before
|
||||
background-color: $custom-control-indicator-checked-disabled-bg
|
||||
|
||||
// Select
|
||||
//
|
||||
// Replaces the browser default select with a custom one, mostly pulled from
|
||||
// https://primer.github.io/.
|
||||
//
|
||||
|
||||
.custom-select
|
||||
display: inline-block
|
||||
width: 100%
|
||||
height: $custom-select-height
|
||||
padding: $custom-select-padding-y ($custom-select-padding-x + $custom-select-indicator-padding) $custom-select-padding-y $custom-select-padding-x
|
||||
line-height: $custom-select-line-height
|
||||
color: $custom-select-color
|
||||
vertical-align: middle
|
||||
background: $custom-select-bg $custom-select-indicator no-repeat right $custom-select-padding-x center
|
||||
background-size: $custom-select-bg-size
|
||||
border: $custom-select-border-width solid $custom-select-border-color
|
||||
|
||||
@if $enable-rounded
|
||||
border-radius: $custom-select-border-radius
|
||||
@else
|
||||
border-radius: 0
|
||||
|
||||
+box-shadow($custom-select-box-shadow)
|
||||
|
||||
appearance: none
|
||||
|
||||
&:focus
|
||||
border-color: $custom-select-focus-border-color
|
||||
outline: 0
|
||||
|
||||
@if $enable-shadows
|
||||
box-shadow: $custom-select-box-shadow, $custom-select-focus-box-shadow
|
||||
@else
|
||||
box-shadow: $custom-select-focus-box-shadow
|
||||
|
||||
&::-ms-value
|
||||
// For visual consistency with other platforms/browsers,
|
||||
// suppress the default white text on blue background highlight given to
|
||||
// the selected option text when the (still closed) <select> receives focus
|
||||
// in IE and (under certain conditions) Edge.
|
||||
// See https://github.com/twbs/bootstrap/issues/19398.
|
||||
color: $input-color
|
||||
background-color: $input-bg
|
||||
|
||||
&[multiple],
|
||||
&[size]:not([size="1"])
|
||||
height: auto
|
||||
padding-right: $custom-select-padding-x
|
||||
background-image: none
|
||||
|
||||
&:disabled
|
||||
color: $custom-select-disabled-color
|
||||
background-color: $custom-select-disabled-bg
|
||||
|
||||
// Hides the default caret in IE11
|
||||
&::-ms-expand
|
||||
opacity: 0
|
||||
|
||||
.custom-select-sm
|
||||
height: $custom-select-height-sm
|
||||
padding-top: $custom-select-padding-y
|
||||
padding-bottom: $custom-select-padding-y
|
||||
font-size: $custom-select-font-size-sm
|
||||
|
||||
.custom-select-lg
|
||||
height: $custom-select-height-lg
|
||||
padding-top: $custom-select-padding-y
|
||||
padding-bottom: $custom-select-padding-y
|
||||
font-size: $custom-select-font-size-lg
|
||||
|
||||
// File
|
||||
//
|
||||
// Custom file input.
|
||||
|
||||
.custom-file
|
||||
position: relative
|
||||
display: inline-block
|
||||
width: 100%
|
||||
height: $custom-file-height
|
||||
margin-bottom: 0
|
||||
|
||||
.custom-file-input
|
||||
position: relative
|
||||
z-index: 2
|
||||
width: 100%
|
||||
height: $custom-file-height
|
||||
margin: 0
|
||||
opacity: 0
|
||||
|
||||
&:focus ~ .custom-file-label
|
||||
border-color: $custom-file-focus-border-color
|
||||
box-shadow: $custom-file-focus-box-shadow
|
||||
|
||||
&::after
|
||||
border-color: $custom-file-focus-border-color
|
||||
|
||||
&:disabled ~ .custom-file-label
|
||||
background-color: $custom-file-disabled-bg
|
||||
|
||||
@each $lang, $value in $custom-file-text
|
||||
&:lang(#{$lang}) ~ .custom-file-label::after
|
||||
content: $value
|
||||
|
||||
.custom-file-label
|
||||
position: absolute
|
||||
top: 0
|
||||
right: 0
|
||||
left: 0
|
||||
z-index: 1
|
||||
height: $custom-file-height
|
||||
padding: $custom-file-padding-y $custom-file-padding-x
|
||||
line-height: $custom-file-line-height
|
||||
color: $custom-file-color
|
||||
background-color: $custom-file-bg
|
||||
border: $custom-file-border-width solid $custom-file-border-color
|
||||
|
||||
+border-radius($custom-file-border-radius)
|
||||
+box-shadow($custom-file-box-shadow)
|
||||
|
||||
&::after
|
||||
position: absolute
|
||||
top: 0
|
||||
right: 0
|
||||
bottom: 0
|
||||
z-index: 3
|
||||
display: block
|
||||
height: $custom-file-height-inner
|
||||
padding: $custom-file-padding-y $custom-file-padding-x
|
||||
line-height: $custom-file-line-height
|
||||
color: $custom-file-button-color
|
||||
content: "Browse"
|
||||
|
||||
+gradient-bg($custom-file-button-bg)
|
||||
|
||||
border-left: $custom-file-border-width solid $custom-file-border-color
|
||||
|
||||
+border-radius(0 $custom-file-border-radius $custom-file-border-radius 0)
|
||||
|
||||
// Range
|
||||
//
|
||||
// Style range inputs the same across browsers. Vendor-specific rules for pseudo
|
||||
// elements cannot be mixed. As such, there are no shared styles for focus or
|
||||
// active states on prefixed selectors.
|
||||
|
||||
.custom-range
|
||||
width: 100%
|
||||
padding-left: 0
|
||||
|
||||
// Firefox specific
|
||||
background-color: transparent
|
||||
appearance: none
|
||||
|
||||
&:focus
|
||||
outline: none
|
||||
|
||||
&::-moz-focus-outer
|
||||
border: 0
|
||||
|
||||
&::-webkit-slider-thumb
|
||||
width: $custom-range-thumb-width
|
||||
height: $custom-range-thumb-height
|
||||
margin-top: -($custom-range-thumb-width * 0.25)
|
||||
|
||||
// Webkit specific?
|
||||
+gradient-bg($custom-range-thumb-bg)
|
||||
|
||||
border: $custom-range-thumb-border
|
||||
|
||||
+border-radius($custom-range-thumb-border-radius)
|
||||
+box-shadow($custom-range-thumb-box-shadow)
|
||||
+transition($custom-forms-transition)
|
||||
|
||||
appearance: none
|
||||
|
||||
&:focus
|
||||
outline: none
|
||||
box-shadow: $custom-range-thumb-focus-box-shadow
|
||||
|
||||
// No mixin for focus accessibility
|
||||
|
||||
&:active
|
||||
+gradient-bg($custom-range-thumb-active-bg)
|
||||
|
||||
&::-webkit-slider-runnable-track
|
||||
width: $custom-range-track-width
|
||||
height: $custom-range-track-height
|
||||
color: transparent
|
||||
|
||||
// Why?
|
||||
cursor: $custom-range-track-cursor
|
||||
background-color: $custom-range-track-bg
|
||||
border-color: transparent
|
||||
|
||||
+border-radius($custom-range-track-border-radius)
|
||||
+box-shadow($custom-range-track-box-shadow)
|
||||
|
||||
&::-moz-range-thumb
|
||||
width: $custom-range-thumb-width
|
||||
height: $custom-range-thumb-height
|
||||
|
||||
+gradient-bg($custom-range-thumb-bg)
|
||||
|
||||
border: $custom-range-thumb-border
|
||||
|
||||
+border-radius($custom-range-thumb-border-radius)
|
||||
+box-shadow($custom-range-thumb-box-shadow)
|
||||
+transition($custom-forms-transition)
|
||||
|
||||
appearance: none
|
||||
|
||||
&:focus
|
||||
outline: none
|
||||
box-shadow: $custom-range-thumb-focus-box-shadow
|
||||
|
||||
// No mixin for focus accessibility
|
||||
|
||||
&:active
|
||||
+gradient-bg($custom-range-thumb-active-bg)
|
||||
|
||||
&::-moz-range-track
|
||||
width: $custom-range-track-width
|
||||
height: $custom-range-track-height
|
||||
color: transparent
|
||||
cursor: $custom-range-track-cursor
|
||||
background-color: $custom-range-track-bg
|
||||
border-color: transparent
|
||||
|
||||
// Firefox specific?
|
||||
+border-radius($custom-range-track-border-radius)
|
||||
+box-shadow($custom-range-track-box-shadow)
|
||||
|
||||
&::-ms-thumb
|
||||
width: $custom-range-thumb-width
|
||||
height: $custom-range-thumb-height
|
||||
|
||||
+gradient-bg($custom-range-thumb-bg)
|
||||
|
||||
border: $custom-range-thumb-border
|
||||
|
||||
+border-radius($custom-range-thumb-border-radius)
|
||||
+box-shadow($custom-range-thumb-box-shadow)
|
||||
+transition($custom-forms-transition)
|
||||
|
||||
appearance: none
|
||||
|
||||
&:focus
|
||||
outline: none
|
||||
box-shadow: $custom-range-thumb-focus-box-shadow
|
||||
|
||||
// No mixin for focus accessibility
|
||||
|
||||
&:active
|
||||
+gradient-bg($custom-range-thumb-active-bg)
|
||||
|
||||
&::-ms-track
|
||||
width: $custom-range-track-width
|
||||
height: $custom-range-track-height
|
||||
color: transparent
|
||||
cursor: $custom-range-track-cursor
|
||||
background-color: transparent
|
||||
border-color: transparent
|
||||
border-width: $custom-range-thumb-height * 0.5
|
||||
|
||||
+box-shadow($custom-range-track-box-shadow)
|
||||
|
||||
&::-ms-fill-lower
|
||||
background-color: $custom-range-track-bg
|
||||
|
||||
+border-radius($custom-range-track-border-radius)
|
||||
|
||||
&::-ms-fill-upper
|
||||
margin-right: 15px
|
||||
|
||||
// arbitrary?
|
||||
background-color: $custom-range-track-bg
|
||||
|
||||
+border-radius($custom-range-track-border-radius)
|
||||
|
||||
.custom-control-label::before,
|
||||
.custom-file-label,
|
||||
.custom-select
|
||||
+transition($custom-forms-transition)
|
170
static/assets/bootstrap/sass/_dropdown.sass
Normal file
170
static/assets/bootstrap/sass/_dropdown.sass
Normal file
@@ -0,0 +1,170 @@
|
||||
// The dropdown wrapper (`<div>`)
|
||||
.dropup,
|
||||
.dropright,
|
||||
.dropdown,
|
||||
.dropleft
|
||||
position: relative
|
||||
|
||||
.dropdown-toggle
|
||||
// Generate the caret automatically
|
||||
+caret
|
||||
|
||||
// The dropdown menu
|
||||
.dropdown-menu
|
||||
position: absolute
|
||||
top: 100%
|
||||
left: 0
|
||||
z-index: $zindex-dropdown
|
||||
display: none
|
||||
|
||||
// none by default, but block on "open" of the menu
|
||||
float: left
|
||||
min-width: $dropdown-min-width
|
||||
padding: $dropdown-padding-y 0
|
||||
margin: $dropdown-spacer 0 0
|
||||
|
||||
// override default ul
|
||||
font-size: $font-size-base
|
||||
|
||||
// Redeclare because nesting can cause inheritance issues
|
||||
color: $body-color
|
||||
text-align: left
|
||||
|
||||
// Ensures proper alignment if parent has it changed (e.g., modal footer)
|
||||
list-style: none
|
||||
background-color: $dropdown-bg
|
||||
background-clip: padding-box
|
||||
border: $dropdown-border-width solid $dropdown-border-color
|
||||
|
||||
+border-radius($dropdown-border-radius)
|
||||
+box-shadow($dropdown-box-shadow)
|
||||
|
||||
.dropdown-menu-right
|
||||
right: 0
|
||||
left: auto
|
||||
|
||||
// Allow for dropdowns to go bottom up (aka, dropup-menu)
|
||||
// Just add .dropup after the standard .dropdown class and you're set.
|
||||
.dropup
|
||||
.dropdown-menu
|
||||
top: auto
|
||||
bottom: 100%
|
||||
margin-top: 0
|
||||
margin-bottom: $dropdown-spacer
|
||||
|
||||
.dropdown-toggle
|
||||
+caret(up)
|
||||
|
||||
.dropright
|
||||
.dropdown-menu
|
||||
top: 0
|
||||
right: auto
|
||||
left: 100%
|
||||
margin-top: 0
|
||||
margin-left: $dropdown-spacer
|
||||
|
||||
.dropdown-toggle
|
||||
+caret(right)
|
||||
|
||||
&::after
|
||||
vertical-align: 0
|
||||
|
||||
.dropleft
|
||||
.dropdown-menu
|
||||
top: 0
|
||||
right: 100%
|
||||
left: auto
|
||||
margin-top: 0
|
||||
margin-right: $dropdown-spacer
|
||||
|
||||
.dropdown-toggle
|
||||
+caret(left)
|
||||
|
||||
&::before
|
||||
vertical-align: 0
|
||||
|
||||
// When enabled Popper.js, reset basic dropdown position
|
||||
// stylelint-disable no-duplicate-selectors
|
||||
.dropdown-menu
|
||||
&[x-placement^="top"],
|
||||
&[x-placement^="right"],
|
||||
&[x-placement^="bottom"],
|
||||
&[x-placement^="left"]
|
||||
right: auto
|
||||
bottom: auto
|
||||
|
||||
// stylelint-enable no-duplicate-selectors
|
||||
|
||||
// Dividers (basically an `<hr>`) within the dropdown
|
||||
.dropdown-divider
|
||||
+nav-divider($dropdown-divider-bg)
|
||||
|
||||
// Links, buttons, and more within the dropdown menu
|
||||
//
|
||||
// `<button>`-specific styles are denoted with `// For <button>s`
|
||||
.dropdown-item
|
||||
display: block
|
||||
width: 100%
|
||||
|
||||
// For `<button>`s
|
||||
padding: $dropdown-item-padding-y $dropdown-item-padding-x
|
||||
clear: both
|
||||
font-weight: $font-weight-normal
|
||||
color: $dropdown-link-color
|
||||
text-align: inherit
|
||||
|
||||
// For `<button>`s
|
||||
white-space: nowrap
|
||||
|
||||
// prevent links from randomly breaking onto new lines
|
||||
background-color: transparent
|
||||
|
||||
// For `<button>`s
|
||||
border: 0
|
||||
|
||||
// For `<button>`s
|
||||
|
||||
+hover-focus
|
||||
color: $dropdown-link-hover-color
|
||||
text-decoration: none
|
||||
|
||||
+gradient-bg($dropdown-link-hover-bg)
|
||||
|
||||
|
||||
&.active,
|
||||
&:active
|
||||
color: $dropdown-link-active-color
|
||||
text-decoration: none
|
||||
|
||||
+gradient-bg($dropdown-link-active-bg)
|
||||
|
||||
&.disabled,
|
||||
&:disabled
|
||||
color: $dropdown-link-disabled-color
|
||||
background-color: transparent
|
||||
|
||||
// Remove CSS gradients if they're enabled
|
||||
@if $enable-gradients
|
||||
background-image: none
|
||||
|
||||
.dropdown-menu.show
|
||||
display: block
|
||||
|
||||
// Dropdown section headers
|
||||
.dropdown-header
|
||||
display: block
|
||||
padding: $dropdown-padding-y $dropdown-item-padding-x
|
||||
margin-bottom: 0
|
||||
|
||||
// for use with heading elements
|
||||
font-size: $font-size-sm
|
||||
color: $dropdown-header-color
|
||||
white-space: nowrap
|
||||
|
||||
// as with > li > a
|
||||
|
||||
// Dropdown text
|
||||
.dropdown-item-text
|
||||
display: block
|
||||
padding: $dropdown-item-padding-y $dropdown-item-padding-x
|
||||
color: $dropdown-link-color
|
306
static/assets/bootstrap/sass/_forms.sass
Normal file
306
static/assets/bootstrap/sass/_forms.sass
Normal file
@@ -0,0 +1,306 @@
|
||||
// stylelint-disable selector-no-qualifying-type
|
||||
|
||||
//
|
||||
// Textual form controls
|
||||
//
|
||||
|
||||
.form-control
|
||||
display: block
|
||||
width: 100%
|
||||
padding: $input-padding-y $input-padding-x
|
||||
font-size: $font-size-base
|
||||
line-height: $input-line-height
|
||||
color: $input-color
|
||||
background-color: $input-bg
|
||||
background-clip: padding-box
|
||||
border: $input-border-width solid $input-border-color
|
||||
|
||||
// Note: This has no effect on <select>s in some browsers, due to the limited stylability of `<select>`s in CSS.
|
||||
@if $enable-rounded
|
||||
// Manually use the if/else instead of the mixin to account for iOS override
|
||||
border-radius: $input-border-radius
|
||||
@else
|
||||
// Otherwise undo the iOS default
|
||||
border-radius: 0
|
||||
|
||||
+box-shadow($input-box-shadow)
|
||||
+transition($input-transition)
|
||||
|
||||
// Unstyle the caret on `<select>`s in IE10+.
|
||||
&::-ms-expand
|
||||
background-color: transparent
|
||||
border: 0
|
||||
|
||||
// Customize the `:focus` state to imitate native WebKit styles.
|
||||
+form-control-focus
|
||||
|
||||
// Placeholder
|
||||
&::placeholder
|
||||
color: $input-placeholder-color
|
||||
|
||||
// Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526.
|
||||
opacity: 1
|
||||
|
||||
// Disabled and read-only inputs
|
||||
//
|
||||
// HTML5 says that controls under a fieldset > legend:first-child won't be
|
||||
// disabled if the fieldset is disabled. Due to implementation difficulty, we
|
||||
// don't honor that edge case; we style them as disabled anyway.
|
||||
&:disabled,
|
||||
&[readonly]
|
||||
background-color: $input-disabled-bg
|
||||
|
||||
// iOS fix for unreadable disabled content; see https://github.com/twbs/bootstrap/issues/11655.
|
||||
opacity: 1
|
||||
|
||||
select.form-control
|
||||
&:not([size]):not([multiple])
|
||||
height: $input-height
|
||||
|
||||
&:focus::-ms-value
|
||||
// Suppress the nested default white text on blue background highlight given to
|
||||
// the selected option text when the (still closed) <select> receives focus
|
||||
// in IE and (under certain conditions) Edge, as it looks bad and cannot be made to
|
||||
// match the appearance of the native widget.
|
||||
// See https://github.com/twbs/bootstrap/issues/19398.
|
||||
color: $input-color
|
||||
background-color: $input-bg
|
||||
|
||||
// Make file inputs better match text inputs by forcing them to new lines.
|
||||
.form-control-file,
|
||||
.form-control-range
|
||||
display: block
|
||||
width: 100%
|
||||
|
||||
//
|
||||
// Labels
|
||||
//
|
||||
|
||||
// For use with horizontal and inline forms, when you need the label (or legend)
|
||||
// text to align with the form controls.
|
||||
.col-form-label
|
||||
padding-top: calc(#{$input-padding-y} + #{$input-border-width})
|
||||
padding-bottom: calc(#{$input-padding-y} + #{$input-border-width})
|
||||
margin-bottom: 0
|
||||
|
||||
// Override the `<label>/<legend>` default
|
||||
font-size: inherit
|
||||
|
||||
// Override the `<legend>` default
|
||||
line-height: $input-line-height
|
||||
|
||||
.col-form-label-lg
|
||||
padding-top: calc(#{$input-padding-y-lg} + #{$input-border-width})
|
||||
padding-bottom: calc(#{$input-padding-y-lg} + #{$input-border-width})
|
||||
font-size: $font-size-lg
|
||||
line-height: $input-line-height-lg
|
||||
|
||||
.col-form-label-sm
|
||||
padding-top: calc(#{$input-padding-y-sm} + #{$input-border-width})
|
||||
padding-bottom: calc(#{$input-padding-y-sm} + #{$input-border-width})
|
||||
font-size: $font-size-sm
|
||||
line-height: $input-line-height-sm
|
||||
|
||||
// Readonly controls as plain text
|
||||
//
|
||||
// Apply class to a readonly input to make it appear like regular plain
|
||||
// text (without any border, background color, focus indicator)
|
||||
|
||||
.form-control-plaintext
|
||||
display: block
|
||||
width: 100%
|
||||
padding-top: $input-padding-y
|
||||
padding-bottom: $input-padding-y
|
||||
margin-bottom: 0
|
||||
|
||||
// match inputs if this class comes on inputs with default margins
|
||||
line-height: $input-line-height
|
||||
color: $input-plaintext-color
|
||||
background-color: transparent
|
||||
border: solid transparent
|
||||
border-width: $input-border-width 0
|
||||
|
||||
&.form-control-sm,
|
||||
&.form-control-lg
|
||||
padding-right: 0
|
||||
padding-left: 0
|
||||
|
||||
// Form control sizing
|
||||
//
|
||||
// Build on `.form-control` with modifier classes to decrease or increase the
|
||||
// height and font-size of form controls.
|
||||
//
|
||||
// The `.form-group-* form-control` variations are sadly duplicated to avoid the
|
||||
// issue documented in https://github.com/twbs/bootstrap/issues/15074.
|
||||
|
||||
.form-control-sm
|
||||
padding: $input-padding-y-sm $input-padding-x-sm
|
||||
font-size: $font-size-sm
|
||||
line-height: $input-line-height-sm
|
||||
|
||||
+border-radius($input-border-radius-sm)
|
||||
|
||||
select.form-control-sm
|
||||
&:not([size]):not([multiple])
|
||||
height: $input-height-sm
|
||||
|
||||
.form-control-lg
|
||||
padding: $input-padding-y-lg $input-padding-x-lg
|
||||
font-size: $font-size-lg
|
||||
line-height: $input-line-height-lg
|
||||
|
||||
+border-radius($input-border-radius-lg)
|
||||
|
||||
select.form-control-lg
|
||||
&:not([size]):not([multiple])
|
||||
height: $input-height-lg
|
||||
|
||||
// Form groups
|
||||
//
|
||||
// Designed to help with the organization and spacing of vertical forms. For
|
||||
// horizontal forms, use the predefined grid classes.
|
||||
|
||||
.form-group
|
||||
margin-bottom: $form-group-margin-bottom
|
||||
|
||||
.form-text
|
||||
display: block
|
||||
margin-top: $form-text-margin-top
|
||||
|
||||
// Form grid
|
||||
//
|
||||
// Special replacement for our grid system's `.row` for tighter form layouts.
|
||||
|
||||
.form-row
|
||||
display: flex
|
||||
flex-wrap: wrap
|
||||
margin-right: -5px
|
||||
margin-left: -5px
|
||||
|
||||
> .col,
|
||||
> [class*="col-"]
|
||||
padding-right: 5px
|
||||
padding-left: 5px
|
||||
|
||||
// Checkboxes and radios
|
||||
//
|
||||
// Indent the labels to position radios/checkboxes as hanging controls.
|
||||
|
||||
.form-check
|
||||
position: relative
|
||||
display: block
|
||||
padding-left: $form-check-input-gutter
|
||||
|
||||
.form-check-input
|
||||
position: absolute
|
||||
margin-top: $form-check-input-margin-y
|
||||
margin-left: -$form-check-input-gutter
|
||||
|
||||
&:disabled ~ .form-check-label
|
||||
color: $text-muted
|
||||
|
||||
.form-check-label
|
||||
margin-bottom: 0
|
||||
|
||||
// Override default `<label>` bottom margin
|
||||
|
||||
.form-check-inline
|
||||
display: inline-flex
|
||||
align-items: center
|
||||
padding-left: 0
|
||||
|
||||
// Override base .form-check
|
||||
margin-right: $form-check-inline-margin-x
|
||||
|
||||
// Undo .form-check-input defaults and add some `margin-right`.
|
||||
.form-check-input
|
||||
position: static
|
||||
margin-top: 0
|
||||
margin-right: $form-check-inline-input-margin-x
|
||||
margin-left: 0
|
||||
|
||||
// Form validation
|
||||
//
|
||||
// Provide feedback to users when form field values are valid or invalid. Works
|
||||
// primarily for client-side validation via scoped `:invalid` and `:valid`
|
||||
// pseudo-classes but also includes `.is-invalid` and `.is-valid` classes for
|
||||
// server side validation.
|
||||
|
||||
+form-validation-state("valid", $form-feedback-valid-color)
|
||||
+form-validation-state("invalid", $form-feedback-invalid-color)
|
||||
|
||||
// Inline forms
|
||||
//
|
||||
// Make forms appear inline(-block) by adding the `.form-inline` class. Inline
|
||||
// forms begin stacked on extra small (mobile) devices and then go inline when
|
||||
// viewports reach <768px.
|
||||
//
|
||||
// Requires wrapping inputs and labels with `.form-group` for proper display of
|
||||
// default HTML form controls and our custom form controls (e.g., input groups).
|
||||
|
||||
.form-inline
|
||||
display: flex
|
||||
flex-flow: row wrap
|
||||
align-items: center
|
||||
|
||||
// Prevent shorter elements from growing to same height as others (e.g., small buttons growing to normal sized button height)
|
||||
|
||||
// Because we use flex, the initial sizing of checkboxes is collapsed and
|
||||
// doesn't occupy the full-width (which is what we want for xs grid tier),
|
||||
// so we force that here.
|
||||
.form-check
|
||||
width: 100%
|
||||
|
||||
// Kick in the inline
|
||||
+media-breakpoint-up(sm)
|
||||
label
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: center
|
||||
margin-bottom: 0
|
||||
|
||||
// Inline-block all the things for "inline"
|
||||
.form-group
|
||||
display: flex
|
||||
flex: 0 0 auto
|
||||
flex-flow: row wrap
|
||||
align-items: center
|
||||
margin-bottom: 0
|
||||
|
||||
// Allow folks to *not* use `.form-group`
|
||||
.form-control
|
||||
display: inline-block
|
||||
width: auto
|
||||
|
||||
// Prevent labels from stacking above inputs in `.form-group`
|
||||
vertical-align: middle
|
||||
|
||||
// Make static controls behave like regular ones
|
||||
.form-control-plaintext
|
||||
display: inline-block
|
||||
|
||||
.input-group,
|
||||
.custom-select
|
||||
width: auto
|
||||
|
||||
// Remove default margin on radios/checkboxes that were used for stacking, and
|
||||
// then undo the floating of radios and checkboxes to match.
|
||||
.form-check
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: center
|
||||
width: auto
|
||||
padding-left: 0
|
||||
|
||||
.form-check-input
|
||||
position: relative
|
||||
margin-top: 0
|
||||
margin-right: $form-check-input-margin-x
|
||||
margin-left: 0
|
||||
|
||||
.custom-control
|
||||
align-items: center
|
||||
justify-content: center
|
||||
|
||||
.custom-control-label
|
||||
margin-bottom: 0
|
76
static/assets/bootstrap/sass/_functions.sass
Normal file
76
static/assets/bootstrap/sass/_functions.sass
Normal file
@@ -0,0 +1,76 @@
|
||||
// Bootstrap functions
|
||||
//
|
||||
// Utility mixins and functions for evaluating source code across our variables, maps, and mixins.
|
||||
|
||||
// Ascending
|
||||
// Used to evaluate Sass maps like our grid breakpoints.
|
||||
=_assert-ascending($map, $map-name)
|
||||
$prev-key: null
|
||||
$prev-num: null
|
||||
|
||||
@each $key, $num in $map
|
||||
@if $prev-num == null
|
||||
// Do nothing
|
||||
@else if not comparable($prev-num, $num)
|
||||
@warn "Potentially invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} whose unit makes it incomparable to #{$prev-num}, the value of the previous key '#{$prev-key}' !"
|
||||
@else if $prev-num >= $num
|
||||
@warn "Invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} which isn't greater than #{$prev-num}, the value of the previous key '#{$prev-key}' !"
|
||||
|
||||
$prev-key: $key
|
||||
$prev-num: $num
|
||||
|
||||
// Starts at zero
|
||||
// Another grid mixin that ensures the min-width of the lowest breakpoint starts at 0.
|
||||
=_assert-starts-at-zero($map)
|
||||
$values: map-values($map)
|
||||
$first-value: nth($values, 1)
|
||||
|
||||
@if $first-value != 0
|
||||
@warn "First breakpoint in `$grid-breakpoints` must start at 0, but starts at #{$first-value}."
|
||||
|
||||
// Replace `$search` with `$replace` in `$string`
|
||||
// Used on our SVG icon backgrounds for custom forms.
|
||||
//
|
||||
// @author Hugo Giraudel
|
||||
// @param {String} $string - Initial string
|
||||
// @param {String} $search - Substring to replace
|
||||
// @param {String} $replace ('') - New value
|
||||
// @return {String} - Updated string
|
||||
@function str-replace($string, $search, $replace: "")
|
||||
$index: str-index($string, $search)
|
||||
|
||||
@if $index
|
||||
@return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace)
|
||||
|
||||
@return $string
|
||||
|
||||
// Color contrast
|
||||
@function color-yiq($color)
|
||||
$r: red($color)
|
||||
$g: green($color)
|
||||
$b: blue($color)
|
||||
|
||||
$yiq: ($r * 299 + $g * 587 + $b * 114) / 1000
|
||||
|
||||
@if $yiq >= $yiq-contrasted-threshold
|
||||
@return $yiq-text-dark
|
||||
@else
|
||||
@return $yiq-text-light
|
||||
|
||||
// Retrieve color Sass maps
|
||||
@function color($key: "blue")
|
||||
@return map-get($colors, $key)
|
||||
|
||||
@function theme-color($key: "primary")
|
||||
@return map-get($theme-colors, $key)
|
||||
|
||||
@function gray($key: "100")
|
||||
@return map-get($grays, $key)
|
||||
|
||||
// Request a theme color level
|
||||
@function theme-color-level($color-name: "primary", $level: 0)
|
||||
$color: theme-color($color-name)
|
||||
$color-base: if($level > 0, $black, $white)
|
||||
$level: abs($level)
|
||||
|
||||
@return mix($color-base, $color, $level * $theme-color-interval)
|
43
static/assets/bootstrap/sass/_grid.sass
Normal file
43
static/assets/bootstrap/sass/_grid.sass
Normal file
@@ -0,0 +1,43 @@
|
||||
// Container widths
|
||||
//
|
||||
// Set the container width, and override it for fixed navbars in media queries.
|
||||
|
||||
@if $enable-grid-classes
|
||||
.container
|
||||
+make-container
|
||||
+make-container-max-widths
|
||||
|
||||
// Fluid container
|
||||
//
|
||||
// Utilizes the mixin meant for fixed width containers, but with 100% width for
|
||||
// fluid, full width layouts.
|
||||
|
||||
@if $enable-grid-classes
|
||||
.container-fluid
|
||||
+make-container
|
||||
|
||||
// Row
|
||||
//
|
||||
// Rows contain and clear the floats of your columns.
|
||||
|
||||
@if $enable-grid-classes
|
||||
.row
|
||||
+make-row
|
||||
|
||||
// Remove the negative margin from default .row, then the horizontal padding
|
||||
// from all immediate children columns (to prevent runaway style inheritance).
|
||||
.no-gutters
|
||||
margin-right: 0
|
||||
margin-left: 0
|
||||
|
||||
> .col,
|
||||
> [class*="col-"]
|
||||
padding-right: 0
|
||||
padding-left: 0
|
||||
|
||||
// Columns
|
||||
//
|
||||
// Common styles for small and large grid columns
|
||||
|
||||
@if $enable-grid-classes
|
||||
+make-grid-columns
|
37
static/assets/bootstrap/sass/_images.sass
Normal file
37
static/assets/bootstrap/sass/_images.sass
Normal file
@@ -0,0 +1,37 @@
|
||||
// Responsive images (ensure images don't scale beyond their parents)
|
||||
//
|
||||
// This is purposefully opt-in via an explicit class rather than being the default for all `<img>`s.
|
||||
// We previously tried the "images are responsive by default" approach in Bootstrap v2,
|
||||
// and abandoned it in Bootstrap v3 because it breaks lots of third-party widgets (including Google Maps)
|
||||
// which weren't expecting the images within themselves to be involuntarily resized.
|
||||
// See also https://github.com/twbs/bootstrap/issues/18178
|
||||
.img-fluid
|
||||
+img-fluid
|
||||
|
||||
// Image thumbnails
|
||||
.img-thumbnail
|
||||
padding: $thumbnail-padding
|
||||
background-color: $thumbnail-bg
|
||||
border: $thumbnail-border-width solid $thumbnail-border-color
|
||||
|
||||
+border-radius($thumbnail-border-radius)
|
||||
+box-shadow($thumbnail-box-shadow)
|
||||
|
||||
// Keep them at most 100% wide
|
||||
+img-fluid
|
||||
|
||||
//
|
||||
// Figures
|
||||
//
|
||||
|
||||
.figure
|
||||
// Ensures the caption's text aligns with the image.
|
||||
display: inline-block
|
||||
|
||||
.figure-img
|
||||
margin-bottom: $spacer / 2
|
||||
line-height: 1
|
||||
|
||||
.figure-caption
|
||||
font-size: $figure-caption-font-size
|
||||
color: $figure-caption-color
|
159
static/assets/bootstrap/sass/_input-group.sass
Normal file
159
static/assets/bootstrap/sass/_input-group.sass
Normal file
@@ -0,0 +1,159 @@
|
||||
// stylelint-disable selector-no-qualifying-type
|
||||
|
||||
//
|
||||
// Base styles
|
||||
//
|
||||
|
||||
.input-group
|
||||
position: relative
|
||||
display: flex
|
||||
flex-wrap: wrap
|
||||
|
||||
// For form validation feedback
|
||||
align-items: stretch
|
||||
width: 100%
|
||||
|
||||
> .form-control,
|
||||
> .custom-select,
|
||||
> .custom-file
|
||||
position: relative
|
||||
|
||||
// For focus state's z-index
|
||||
flex: 1 1 auto
|
||||
|
||||
// Add width 1% and flex-basis auto to ensure that button will not wrap out
|
||||
// the column. Applies to IE Edge+ and Firefox. Chrome does not require this.
|
||||
width: 1%
|
||||
margin-bottom: 0
|
||||
|
||||
+ .form-control,
|
||||
+ .custom-select,
|
||||
+ .custom-file
|
||||
margin-left: -$input-border-width
|
||||
|
||||
// Bring the "active" form control to the top of surrounding elements
|
||||
> .form-control:focus,
|
||||
> .custom-select:focus,
|
||||
> .custom-file .custom-file-input:focus ~ .custom-file-label
|
||||
z-index: 3
|
||||
|
||||
> .form-control,
|
||||
> .custom-select
|
||||
&:not(:last-child)
|
||||
+border-right-radius(0)
|
||||
|
||||
&:not(:first-child)
|
||||
+border-left-radius(0)
|
||||
|
||||
// Custom file inputs have more complex markup, thus requiring different
|
||||
// border-radius overrides.
|
||||
> .custom-file
|
||||
display: flex
|
||||
align-items: center
|
||||
|
||||
&:not(:last-child) .custom-file-label,
|
||||
&:not(:last-child) .custom-file-label::after
|
||||
+border-right-radius(0)
|
||||
|
||||
&:not(:first-child) .custom-file-label
|
||||
+border-left-radius(0)
|
||||
|
||||
// Prepend and append
|
||||
//
|
||||
// While it requires one extra layer of HTML for each, dedicated prepend and
|
||||
// append elements allow us to 1) be less clever, 2) simplify our selectors, and
|
||||
// 3) support HTML5 form validation.
|
||||
|
||||
.input-group-prepend,
|
||||
.input-group-append
|
||||
display: flex
|
||||
|
||||
// Ensure buttons are always above inputs for more visually pleasing borders.
|
||||
// This isn't needed for `.input-group-text` since it shares the same border-color
|
||||
// as our inputs.
|
||||
.btn
|
||||
position: relative
|
||||
z-index: 2
|
||||
|
||||
.btn + .btn,
|
||||
.btn + .input-group-text,
|
||||
.input-group-text + .input-group-text,
|
||||
.input-group-text + .btn
|
||||
margin-left: -$input-border-width
|
||||
|
||||
.input-group-prepend
|
||||
margin-right: -$input-border-width
|
||||
|
||||
.input-group-append
|
||||
margin-left: -$input-border-width
|
||||
|
||||
// Textual addons
|
||||
//
|
||||
// Serves as a catch-all element for any text or radio/checkbox input you wish
|
||||
// to prepend or append to an input.
|
||||
|
||||
.input-group-text
|
||||
display: flex
|
||||
align-items: center
|
||||
padding: $input-padding-y $input-padding-x
|
||||
margin-bottom: 0
|
||||
|
||||
// Allow use of <label> elements by overriding our default margin-bottom
|
||||
font-size: $font-size-base
|
||||
|
||||
// Match inputs
|
||||
font-weight: $font-weight-normal
|
||||
line-height: $input-line-height
|
||||
color: $input-group-addon-color
|
||||
text-align: center
|
||||
white-space: nowrap
|
||||
background-color: $input-group-addon-bg
|
||||
border: $input-border-width solid $input-group-addon-border-color
|
||||
|
||||
+border-radius($input-border-radius)
|
||||
|
||||
// Nuke default margins from checkboxes and radios to vertically center within.
|
||||
input[type="radio"],
|
||||
input[type="checkbox"]
|
||||
margin-top: 0
|
||||
|
||||
// Sizing
|
||||
//
|
||||
// Remix the default form control sizing classes into new ones for easier
|
||||
// manipulation.
|
||||
|
||||
.input-group-lg > .form-control,
|
||||
.input-group-lg > .input-group-prepend > .input-group-text,
|
||||
.input-group-lg > .input-group-append > .input-group-text,
|
||||
.input-group-lg > .input-group-prepend > .btn,
|
||||
.input-group-lg > .input-group-append > .btn
|
||||
@extend .form-control-lg
|
||||
|
||||
.input-group-sm > .form-control,
|
||||
.input-group-sm > .input-group-prepend > .input-group-text,
|
||||
.input-group-sm > .input-group-append > .input-group-text,
|
||||
.input-group-sm > .input-group-prepend > .btn,
|
||||
.input-group-sm > .input-group-append > .btn
|
||||
@extend .form-control-sm
|
||||
|
||||
// Prepend and append rounded corners
|
||||
//
|
||||
// These rulesets must come after the sizing ones to properly override sm and lg
|
||||
// border-radius values when extending. They're more specific than we'd like
|
||||
// with the `.input-group >` part, but without it, we cannot override the sizing.
|
||||
|
||||
.input-group > .input-group-prepend > .btn,
|
||||
.input-group > .input-group-prepend > .input-group-text,
|
||||
.input-group > .input-group-append:not(:last-child) > .btn,
|
||||
.input-group > .input-group-append:not(:last-child) > .input-group-text,
|
||||
.input-group > .input-group-append:last-child > .btn:not(:last-child):not(.dropdown-toggle),
|
||||
.input-group > .input-group-append:last-child > .input-group-text:not(:last-child)
|
||||
+border-right-radius(0)
|
||||
|
||||
.input-group > .input-group-append > .btn,
|
||||
.input-group > .input-group-append > .input-group-text,
|
||||
.input-group > .input-group-prepend:not(:first-child) > .btn,
|
||||
.input-group > .input-group-prepend:not(:first-child) > .input-group-text,
|
||||
.input-group > .input-group-prepend:first-child > .btn:not(:first-child),
|
||||
.input-group > .input-group-prepend:first-child > .input-group-text:not(:first-child)
|
||||
+border-left-radius(0)
|
15
static/assets/bootstrap/sass/_jumbotron.sass
Normal file
15
static/assets/bootstrap/sass/_jumbotron.sass
Normal file
@@ -0,0 +1,15 @@
|
||||
.jumbotron
|
||||
padding: $jumbotron-padding ($jumbotron-padding / 2)
|
||||
margin-bottom: $jumbotron-padding
|
||||
background-color: $jumbotron-bg
|
||||
|
||||
+border-radius($border-radius-lg)
|
||||
|
||||
+media-breakpoint-up(sm)
|
||||
padding: ($jumbotron-padding * 2) $jumbotron-padding
|
||||
|
||||
.jumbotron-fluid
|
||||
padding-right: 0
|
||||
padding-left: 0
|
||||
|
||||
+border-radius(0)
|
109
static/assets/bootstrap/sass/_list-group.sass
Normal file
109
static/assets/bootstrap/sass/_list-group.sass
Normal file
@@ -0,0 +1,109 @@
|
||||
// Base class
|
||||
//
|
||||
// Easily usable on <ul>, <ol>, or <div>.
|
||||
|
||||
.list-group
|
||||
display: flex
|
||||
flex-direction: column
|
||||
|
||||
// No need to set list-style: none; since .list-group-item is block level
|
||||
padding-left: 0
|
||||
|
||||
// reset padding because ul and ol
|
||||
margin-bottom: 0
|
||||
|
||||
// Interactive list items
|
||||
//
|
||||
// Use anchor or button elements instead of `li`s or `div`s to create interactive
|
||||
// list items. Includes an extra `.active` modifier class for selected items.
|
||||
|
||||
.list-group-item-action
|
||||
width: 100%
|
||||
|
||||
// For `<button>`s (anchors become 100% by default though)
|
||||
color: $list-group-action-color
|
||||
text-align: inherit
|
||||
|
||||
// For `<button>`s (anchors inherit)
|
||||
|
||||
// Hover state
|
||||
+hover-focus
|
||||
color: $list-group-action-hover-color
|
||||
text-decoration: none
|
||||
background-color: $list-group-hover-bg
|
||||
|
||||
|
||||
&:active
|
||||
color: $list-group-action-active-color
|
||||
background-color: $list-group-action-active-bg
|
||||
|
||||
// Individual list items
|
||||
//
|
||||
// Use on `li`s or `div`s within the `.list-group` parent.
|
||||
|
||||
.list-group-item
|
||||
position: relative
|
||||
display: block
|
||||
padding: $list-group-item-padding-y $list-group-item-padding-x
|
||||
|
||||
// Place the border on the list items and negative margin up for better styling
|
||||
margin-bottom: -$list-group-border-width
|
||||
background-color: $list-group-bg
|
||||
border: $list-group-border-width solid $list-group-border-color
|
||||
|
||||
&:first-child
|
||||
+border-top-radius($list-group-border-radius)
|
||||
|
||||
&:last-child
|
||||
margin-bottom: 0
|
||||
|
||||
+border-bottom-radius($list-group-border-radius)
|
||||
|
||||
+hover-focus
|
||||
z-index: 1
|
||||
|
||||
// Place hover/active items above their siblings for proper border styling
|
||||
text-decoration: none
|
||||
|
||||
|
||||
&.disabled,
|
||||
&:disabled
|
||||
color: $list-group-disabled-color
|
||||
background-color: $list-group-disabled-bg
|
||||
|
||||
// Include both here for `<a>`s and `<button>`s
|
||||
&.active
|
||||
z-index: 2
|
||||
|
||||
// Place active items above their siblings for proper border styling
|
||||
color: $list-group-active-color
|
||||
background-color: $list-group-active-bg
|
||||
border-color: $list-group-active-border-color
|
||||
|
||||
// Flush list items
|
||||
//
|
||||
// Remove borders and border-radius to keep list group items edge-to-edge. Most
|
||||
// useful within other components (e.g., cards).
|
||||
|
||||
.list-group-flush
|
||||
.list-group-item
|
||||
border-right: 0
|
||||
border-left: 0
|
||||
|
||||
+border-radius(0)
|
||||
|
||||
&:first-child
|
||||
.list-group-item:first-child
|
||||
border-top: 0
|
||||
|
||||
&:last-child
|
||||
.list-group-item:last-child
|
||||
border-bottom: 0
|
||||
|
||||
// Contextual variants
|
||||
//
|
||||
// Add modifier classes to change text and background color on individual items.
|
||||
// Organizationally, this must come after the `:hover` states.
|
||||
|
||||
@each $color, $value in $theme-colors
|
||||
+list-group-item-variant($color, theme-color-level($color, -9), theme-color-level($color, 6))
|
6
static/assets/bootstrap/sass/_media.sass
Normal file
6
static/assets/bootstrap/sass/_media.sass
Normal file
@@ -0,0 +1,6 @@
|
||||
.media
|
||||
display: flex
|
||||
align-items: flex-start
|
||||
|
||||
.media-body
|
||||
flex: 1
|
41
static/assets/bootstrap/sass/_mixins.sass
Normal file
41
static/assets/bootstrap/sass/_mixins.sass
Normal file
@@ -0,0 +1,41 @@
|
||||
// Toggles
|
||||
//
|
||||
// Used in conjunction with global variables to enable certain theme features.
|
||||
|
||||
// Utilities
|
||||
@import mixins/breakpoints
|
||||
@import mixins/hover
|
||||
@import mixins/image
|
||||
@import mixins/badge
|
||||
@import mixins/resize
|
||||
@import mixins/screen-reader
|
||||
@import mixins/size
|
||||
@import mixins/reset-text
|
||||
@import mixins/text-emphasis
|
||||
@import mixins/text-hide
|
||||
@import mixins/text-truncate
|
||||
@import mixins/visibility
|
||||
|
||||
// // Components
|
||||
@import mixins/alert
|
||||
@import mixins/buttons
|
||||
@import mixins/caret
|
||||
@import mixins/pagination
|
||||
@import mixins/lists
|
||||
@import mixins/list-group
|
||||
@import mixins/nav-divider
|
||||
@import mixins/forms
|
||||
@import mixins/table-row
|
||||
|
||||
// // Skins
|
||||
@import mixins/background-variant
|
||||
@import mixins/border-radius
|
||||
@import mixins/box-shadow
|
||||
@import mixins/gradients
|
||||
@import mixins/transition
|
||||
|
||||
// // Layout
|
||||
@import mixins/clearfix
|
||||
@import mixins/grid-framework
|
||||
@import mixins/grid
|
||||
@import mixins/float
|
175
static/assets/bootstrap/sass/_modal.sass
Normal file
175
static/assets/bootstrap/sass/_modal.sass
Normal file
@@ -0,0 +1,175 @@
|
||||
// .modal-open - body class for killing the scroll
|
||||
// .modal - container to scroll within
|
||||
// .modal-dialog - positioning shell for the actual modal
|
||||
// .modal-content - actual modal w/ bg and corners and stuff
|
||||
|
||||
// Kill the scroll on the body
|
||||
.modal-open
|
||||
overflow: hidden
|
||||
|
||||
// Container that the modal scrolls within
|
||||
.modal
|
||||
position: fixed
|
||||
top: 0
|
||||
right: 0
|
||||
bottom: 0
|
||||
left: 0
|
||||
z-index: $zindex-modal
|
||||
display: none
|
||||
overflow: hidden
|
||||
|
||||
// Prevent Chrome on Windows from adding a focus outline. For details, see
|
||||
// https://github.com/twbs/bootstrap/pull/10951.
|
||||
outline: 0
|
||||
|
||||
// We deliberately don't use `-webkit-overflow-scrolling: touch;` due to a
|
||||
// gnarly iOS Safari bug: https://bugs.webkit.org/show_bug.cgi?id=158342
|
||||
// See also https://github.com/twbs/bootstrap/issues/17695
|
||||
|
||||
.modal-open &
|
||||
overflow-x: hidden
|
||||
overflow-y: auto
|
||||
|
||||
// Shell div to position the modal with bottom padding
|
||||
.modal-dialog
|
||||
position: relative
|
||||
width: auto
|
||||
margin: $modal-dialog-margin
|
||||
|
||||
// allow clicks to pass through for custom click handling to close modal
|
||||
pointer-events: none
|
||||
|
||||
// When fading in the modal, animate it to slide down
|
||||
.modal.fade &
|
||||
+transition($modal-transition)
|
||||
|
||||
transform: translate(0, -25%)
|
||||
|
||||
.modal.show &
|
||||
transform: translate(0, 0)
|
||||
|
||||
.modal-dialog-centered
|
||||
display: flex
|
||||
align-items: center
|
||||
min-height: calc(100% - (#{$modal-dialog-margin} * 2))
|
||||
|
||||
// Actual modal
|
||||
.modal-content
|
||||
position: relative
|
||||
display: flex
|
||||
flex-direction: column
|
||||
width: 100%
|
||||
|
||||
// Ensure `.modal-content` extends the full width of the parent `.modal-dialog`
|
||||
// counteract the pointer-events: none; in the .modal-dialog
|
||||
pointer-events: auto
|
||||
background-color: $modal-content-bg
|
||||
background-clip: padding-box
|
||||
border: $modal-content-border-width solid $modal-content-border-color
|
||||
|
||||
+border-radius($modal-content-border-radius)
|
||||
+box-shadow($modal-content-box-shadow-xs)
|
||||
|
||||
// Remove focus outline from opened modal
|
||||
outline: 0
|
||||
|
||||
// Modal background
|
||||
.modal-backdrop
|
||||
position: fixed
|
||||
top: 0
|
||||
right: 0
|
||||
bottom: 0
|
||||
left: 0
|
||||
z-index: $zindex-modal-backdrop
|
||||
background-color: $modal-backdrop-bg
|
||||
|
||||
// Fade for backdrop
|
||||
&.fade
|
||||
opacity: 0
|
||||
|
||||
&.show
|
||||
opacity: $modal-backdrop-opacity
|
||||
|
||||
// Modal header
|
||||
// Top section of the modal w/ title and dismiss
|
||||
.modal-header
|
||||
display: flex
|
||||
align-items: flex-start
|
||||
|
||||
// so the close btn always stays on the upper right corner
|
||||
justify-content: space-between
|
||||
|
||||
// Put modal header elements (title and dismiss) on opposite ends
|
||||
padding: $modal-header-padding
|
||||
border-bottom: $modal-header-border-width solid $modal-header-border-color
|
||||
|
||||
+border-top-radius($modal-content-border-radius)
|
||||
|
||||
.close
|
||||
padding: $modal-header-padding
|
||||
|
||||
// auto on the left force icon to the right even when there is no .modal-title
|
||||
margin: (-$modal-header-padding) (-$modal-header-padding) (-$modal-header-padding) auto
|
||||
|
||||
// Title text within header
|
||||
.modal-title
|
||||
margin-bottom: 0
|
||||
line-height: $modal-title-line-height
|
||||
|
||||
// Modal body
|
||||
// Where all modal content resides (sibling of .modal-header and .modal-footer)
|
||||
.modal-body
|
||||
position: relative
|
||||
|
||||
// Enable `flex-grow: 1` so that the body take up as much space as possible
|
||||
// when should there be a fixed height on `.modal-dialog`.
|
||||
flex: 1 1 auto
|
||||
padding: $modal-inner-padding
|
||||
|
||||
// Footer (for actions)
|
||||
.modal-footer
|
||||
display: flex
|
||||
align-items: center
|
||||
|
||||
// vertically center
|
||||
justify-content: flex-end
|
||||
|
||||
// Right align buttons with flex property because text-align doesn't work on flex items
|
||||
padding: $modal-inner-padding
|
||||
border-top: $modal-footer-border-width solid $modal-footer-border-color
|
||||
|
||||
// Easily place margin between footer elements
|
||||
> :not(:first-child)
|
||||
margin-left: .25rem
|
||||
|
||||
> :not(:last-child)
|
||||
margin-right: .25rem
|
||||
|
||||
// Measure scrollbar width for padding body during modal show/hide
|
||||
.modal-scrollbar-measure
|
||||
position: absolute
|
||||
top: -9999px
|
||||
width: 50px
|
||||
height: 50px
|
||||
overflow: scroll
|
||||
|
||||
// Scale up the modal
|
||||
+media-breakpoint-up(sm)
|
||||
// Automatically set modal's width for larger viewports
|
||||
.modal-dialog
|
||||
max-width: $modal-md
|
||||
margin: $modal-dialog-margin-y-sm-up auto
|
||||
|
||||
.modal-dialog-centered
|
||||
min-height: calc(100% - (#{$modal-dialog-margin-y-sm-up} * 2))
|
||||
|
||||
.modal-content
|
||||
+box-shadow($modal-content-box-shadow-sm-up)
|
||||
|
||||
.modal-sm
|
||||
max-width: $modal-sm
|
||||
|
||||
|
||||
+media-breakpoint-up(lg)
|
||||
.modal-lg
|
||||
max-width: $modal-lg
|
99
static/assets/bootstrap/sass/_nav.sass
Normal file
99
static/assets/bootstrap/sass/_nav.sass
Normal file
@@ -0,0 +1,99 @@
|
||||
// Base class
|
||||
//
|
||||
// Kickstart any navigation component with a set of style resets. Works with
|
||||
// `<nav>`s or `<ul>`s.
|
||||
|
||||
.nav
|
||||
display: flex
|
||||
flex-wrap: wrap
|
||||
padding-left: 0
|
||||
margin-bottom: 0
|
||||
list-style: none
|
||||
|
||||
.nav-link
|
||||
display: block
|
||||
padding: $nav-link-padding-y $nav-link-padding-x
|
||||
|
||||
+hover-focus
|
||||
text-decoration: none
|
||||
|
||||
|
||||
// Disabled state lightens text
|
||||
&.disabled
|
||||
color: $nav-link-disabled-color
|
||||
|
||||
//
|
||||
// Tabs
|
||||
//
|
||||
|
||||
.nav-tabs
|
||||
border-bottom: $nav-tabs-border-width solid $nav-tabs-border-color
|
||||
|
||||
.nav-item
|
||||
margin-bottom: -$nav-tabs-border-width
|
||||
|
||||
.nav-link
|
||||
border: $nav-tabs-border-width solid transparent
|
||||
|
||||
+border-top-radius($nav-tabs-border-radius)
|
||||
|
||||
+hover-focus
|
||||
border-color: $nav-tabs-link-hover-border-color
|
||||
|
||||
|
||||
&.disabled
|
||||
color: $nav-link-disabled-color
|
||||
background-color: transparent
|
||||
border-color: transparent
|
||||
|
||||
.nav-link.active,
|
||||
.nav-item.show .nav-link
|
||||
color: $nav-tabs-link-active-color
|
||||
background-color: $nav-tabs-link-active-bg
|
||||
border-color: $nav-tabs-link-active-border-color
|
||||
|
||||
.dropdown-menu
|
||||
// Make dropdown border overlap tab border
|
||||
margin-top: -$nav-tabs-border-width
|
||||
|
||||
// Remove the top rounded corners here since there is a hard edge above the menu
|
||||
+border-top-radius(0)
|
||||
|
||||
//
|
||||
// Pills
|
||||
//
|
||||
|
||||
.nav-pills
|
||||
.nav-link
|
||||
+border-radius($nav-pills-border-radius)
|
||||
|
||||
.nav-link.active,
|
||||
.show > .nav-link
|
||||
color: $nav-pills-link-active-color
|
||||
background-color: $nav-pills-link-active-bg
|
||||
|
||||
//
|
||||
// Justified variants
|
||||
//
|
||||
|
||||
.nav-fill
|
||||
.nav-item
|
||||
flex: 1 1 auto
|
||||
text-align: center
|
||||
|
||||
.nav-justified
|
||||
.nav-item
|
||||
flex-basis: 0
|
||||
flex-grow: 1
|
||||
text-align: center
|
||||
|
||||
// Tabbable tabs
|
||||
//
|
||||
// Hide tabbable panes to start, show them when `.active`
|
||||
|
||||
.tab-content
|
||||
> .tab-pane
|
||||
display: none
|
||||
|
||||
> .active
|
||||
display: block
|
261
static/assets/bootstrap/sass/_navbar.sass
Normal file
261
static/assets/bootstrap/sass/_navbar.sass
Normal file
@@ -0,0 +1,261 @@
|
||||
// Contents
|
||||
//
|
||||
// Navbar
|
||||
// Navbar brand
|
||||
// Navbar nav
|
||||
// Navbar text
|
||||
// Navbar divider
|
||||
// Responsive navbar
|
||||
// Navbar position
|
||||
// Navbar themes
|
||||
|
||||
// Navbar
|
||||
//
|
||||
// Provide a static navbar from which we expand to create full-width, fixed, and
|
||||
// other navbar variations.
|
||||
|
||||
.navbar
|
||||
position: relative
|
||||
display: flex
|
||||
flex-wrap: wrap
|
||||
|
||||
// allow us to do the line break for collapsing content
|
||||
align-items: center
|
||||
justify-content: space-between
|
||||
|
||||
// space out brand from logo
|
||||
padding: $navbar-padding-y $navbar-padding-x
|
||||
|
||||
// Because flex properties aren't inherited, we need to redeclare these first
|
||||
// few properties so that content nested within behave properly.
|
||||
> .container,
|
||||
> .container-fluid
|
||||
display: flex
|
||||
flex-wrap: wrap
|
||||
align-items: center
|
||||
justify-content: space-between
|
||||
|
||||
// Navbar brand
|
||||
//
|
||||
// Used for brand, project, or site names.
|
||||
|
||||
.navbar-brand
|
||||
display: inline-block
|
||||
padding-top: $navbar-brand-padding-y
|
||||
padding-bottom: $navbar-brand-padding-y
|
||||
margin-right: $navbar-padding-x
|
||||
font-size: $navbar-brand-font-size
|
||||
line-height: inherit
|
||||
white-space: nowrap
|
||||
|
||||
+hover-focus
|
||||
text-decoration: none
|
||||
|
||||
// Navbar nav
|
||||
//
|
||||
// Custom navbar navigation (doesn't require `.nav`, but does make use of `.nav-link`).
|
||||
|
||||
.navbar-nav
|
||||
display: flex
|
||||
flex-direction: column
|
||||
|
||||
// cannot use `inherit` to get the `.navbar`s value
|
||||
padding-left: 0
|
||||
margin-bottom: 0
|
||||
list-style: none
|
||||
|
||||
.nav-link
|
||||
padding-right: 0
|
||||
padding-left: 0
|
||||
|
||||
.dropdown-menu
|
||||
position: static
|
||||
float: none
|
||||
|
||||
// Navbar text
|
||||
//
|
||||
//
|
||||
|
||||
.navbar-text
|
||||
display: inline-block
|
||||
padding-top: $nav-link-padding-y
|
||||
padding-bottom: $nav-link-padding-y
|
||||
|
||||
// Responsive navbar
|
||||
//
|
||||
// Custom styles for responsive collapsing and toggling of navbar contents.
|
||||
// Powered by the collapse Bootstrap JavaScript plugin.
|
||||
|
||||
// When collapsed, prevent the toggleable navbar contents from appearing in
|
||||
// the default flexbox row orientation. Requires the use of `flex-wrap: wrap`
|
||||
// on the `.navbar` parent.
|
||||
.navbar-collapse
|
||||
flex-basis: 100%
|
||||
flex-grow: 1
|
||||
|
||||
// For always expanded or extra full navbars, ensure content aligns itself
|
||||
// properly vertically. Can be easily overridden with flex utilities.
|
||||
align-items: center
|
||||
|
||||
// Button for toggling the navbar when in its collapsed state
|
||||
.navbar-toggler
|
||||
padding: $navbar-toggler-padding-y $navbar-toggler-padding-x
|
||||
font-size: $navbar-toggler-font-size
|
||||
line-height: 1
|
||||
background-color: transparent
|
||||
|
||||
// remove default button style
|
||||
border: $border-width solid transparent
|
||||
|
||||
// remove default button style
|
||||
+border-radius($navbar-toggler-border-radius)
|
||||
|
||||
+hover-focus
|
||||
text-decoration: none
|
||||
|
||||
|
||||
// Opinionated: add "hand" cursor to non-disabled .navbar-toggler elements
|
||||
&:not(:disabled):not(.disabled)
|
||||
cursor: pointer
|
||||
|
||||
// Keep as a separate element so folks can easily override it with another icon
|
||||
// or image file as needed.
|
||||
.navbar-toggler-icon
|
||||
display: inline-block
|
||||
width: 1.5em
|
||||
height: 1.5em
|
||||
vertical-align: middle
|
||||
content: ""
|
||||
background: no-repeat center center
|
||||
background-size: 100% 100%
|
||||
|
||||
// Generate series of `.navbar-expand-*` responsive classes for configuring
|
||||
// where your navbar collapses.
|
||||
.navbar-expand
|
||||
@each $breakpoint in map-keys($grid-breakpoints)
|
||||
$next: breakpoint-next($breakpoint, $grid-breakpoints)
|
||||
$infix: breakpoint-infix($next, $grid-breakpoints)
|
||||
|
||||
&#{$infix}
|
||||
+media-breakpoint-down($breakpoint)
|
||||
> .container,
|
||||
> .container-fluid
|
||||
padding-right: 0
|
||||
padding-left: 0
|
||||
|
||||
|
||||
+media-breakpoint-up($next)
|
||||
flex-flow: row nowrap
|
||||
justify-content: flex-start
|
||||
|
||||
.navbar-nav
|
||||
flex-direction: row
|
||||
|
||||
.dropdown-menu
|
||||
position: absolute
|
||||
|
||||
.nav-link
|
||||
padding-right: $navbar-nav-link-padding-x
|
||||
padding-left: $navbar-nav-link-padding-x
|
||||
|
||||
// For nesting containers, have to redeclare for alignment purposes
|
||||
> .container,
|
||||
> .container-fluid
|
||||
flex-wrap: nowrap
|
||||
|
||||
.navbar-collapse
|
||||
display: flex !important
|
||||
|
||||
// stylelint-disable-line declaration-no-important
|
||||
|
||||
// Changes flex-bases to auto because of an IE10 bug
|
||||
flex-basis: auto
|
||||
|
||||
.navbar-toggler
|
||||
display: none
|
||||
|
||||
// Navbar themes
|
||||
//
|
||||
// Styles for switching between navbars with light or dark background.
|
||||
|
||||
// Dark links against a light background
|
||||
.navbar-light
|
||||
.navbar-brand
|
||||
color: $navbar-light-active-color
|
||||
|
||||
+hover-focus
|
||||
color: $navbar-light-active-color
|
||||
|
||||
.navbar-nav
|
||||
.nav-link
|
||||
color: $navbar-light-color
|
||||
|
||||
+hover-focus
|
||||
color: $navbar-light-hover-color
|
||||
|
||||
|
||||
&.disabled
|
||||
color: $navbar-light-disabled-color
|
||||
|
||||
.show > .nav-link,
|
||||
.active > .nav-link,
|
||||
.nav-link.show,
|
||||
.nav-link.active
|
||||
color: $navbar-light-active-color
|
||||
|
||||
.navbar-toggler
|
||||
color: $navbar-light-color
|
||||
border-color: $navbar-light-toggler-border-color
|
||||
|
||||
.navbar-toggler-icon
|
||||
background-image: $navbar-light-toggler-icon-bg
|
||||
|
||||
.navbar-text
|
||||
color: $navbar-light-color
|
||||
|
||||
a
|
||||
color: $navbar-light-active-color
|
||||
|
||||
+hover-focus
|
||||
color: $navbar-light-active-color
|
||||
|
||||
// White links against a dark background
|
||||
.navbar-dark
|
||||
.navbar-brand
|
||||
color: $navbar-dark-active-color
|
||||
|
||||
+hover-focus
|
||||
color: $navbar-dark-active-color
|
||||
|
||||
.navbar-nav
|
||||
.nav-link
|
||||
color: $navbar-dark-color
|
||||
|
||||
+hover-focus
|
||||
color: $navbar-dark-hover-color
|
||||
|
||||
|
||||
&.disabled
|
||||
color: $navbar-dark-disabled-color
|
||||
|
||||
.show > .nav-link,
|
||||
.active > .nav-link,
|
||||
.nav-link.show,
|
||||
.nav-link.active
|
||||
color: $navbar-dark-active-color
|
||||
|
||||
.navbar-toggler
|
||||
color: $navbar-dark-color
|
||||
border-color: $navbar-dark-toggler-border-color
|
||||
|
||||
.navbar-toggler-icon
|
||||
background-image: $navbar-dark-toggler-icon-bg
|
||||
|
||||
.navbar-text
|
||||
color: $navbar-dark-color
|
||||
|
||||
a
|
||||
color: $navbar-dark-active-color
|
||||
|
||||
+hover-focus
|
||||
color: $navbar-dark-active-color
|
67
static/assets/bootstrap/sass/_pagination.sass
Normal file
67
static/assets/bootstrap/sass/_pagination.sass
Normal file
@@ -0,0 +1,67 @@
|
||||
.pagination
|
||||
display: flex
|
||||
|
||||
+list-unstyled
|
||||
+border-radius
|
||||
|
||||
.page-link
|
||||
position: relative
|
||||
display: block
|
||||
padding: $pagination-padding-y $pagination-padding-x
|
||||
margin-left: -$pagination-border-width
|
||||
line-height: $pagination-line-height
|
||||
color: $pagination-color
|
||||
background-color: $pagination-bg
|
||||
border: $pagination-border-width solid $pagination-border-color
|
||||
|
||||
&:hover
|
||||
z-index: 2
|
||||
color: $pagination-hover-color
|
||||
text-decoration: none
|
||||
background-color: $pagination-hover-bg
|
||||
border-color: $pagination-hover-border-color
|
||||
|
||||
&:focus
|
||||
z-index: 2
|
||||
outline: $pagination-focus-outline
|
||||
box-shadow: $pagination-focus-box-shadow
|
||||
|
||||
// Opinionated: add "hand" cursor to non-disabled .page-link elements
|
||||
&:not(:disabled):not(.disabled)
|
||||
cursor: pointer
|
||||
|
||||
.page-item
|
||||
&:first-child
|
||||
.page-link
|
||||
margin-left: 0
|
||||
|
||||
+border-left-radius($border-radius)
|
||||
|
||||
&:last-child
|
||||
.page-link
|
||||
+border-right-radius($border-radius)
|
||||
|
||||
&.active .page-link
|
||||
z-index: 1
|
||||
color: $pagination-active-color
|
||||
background-color: $pagination-active-bg
|
||||
border-color: $pagination-active-border-color
|
||||
|
||||
&.disabled .page-link
|
||||
color: $pagination-disabled-color
|
||||
pointer-events: none
|
||||
|
||||
// Opinionated: remove the "hand" cursor set previously for .page-link
|
||||
cursor: auto
|
||||
background-color: $pagination-disabled-bg
|
||||
border-color: $pagination-disabled-border-color
|
||||
|
||||
//
|
||||
// Sizing
|
||||
//
|
||||
|
||||
.pagination-lg
|
||||
+pagination-size($pagination-padding-y-lg, $pagination-padding-x-lg, $font-size-lg, $line-height-lg, $border-radius-lg)
|
||||
|
||||
.pagination-sm
|
||||
+pagination-size($pagination-padding-y-sm, $pagination-padding-x-sm, $font-size-sm, $line-height-sm, $border-radius-sm)
|
165
static/assets/bootstrap/sass/_popover.sass
Normal file
165
static/assets/bootstrap/sass/_popover.sass
Normal file
@@ -0,0 +1,165 @@
|
||||
.popover
|
||||
position: absolute
|
||||
top: 0
|
||||
left: 0
|
||||
z-index: $zindex-popover
|
||||
display: block
|
||||
max-width: $popover-max-width
|
||||
|
||||
// Our parent element can be arbitrary since tooltips are by default inserted as a sibling of their target element.
|
||||
// So reset our font and text properties to avoid inheriting weird values.
|
||||
+reset-text
|
||||
|
||||
font-size: $popover-font-size
|
||||
|
||||
// Allow breaking very long words so they don't overflow the popover's bounds
|
||||
word-wrap: break-word
|
||||
background-color: $popover-bg
|
||||
background-clip: padding-box
|
||||
border: $popover-border-width solid $popover-border-color
|
||||
|
||||
+border-radius($popover-border-radius)
|
||||
+box-shadow($popover-box-shadow)
|
||||
|
||||
.arrow
|
||||
position: absolute
|
||||
display: block
|
||||
width: $popover-arrow-width
|
||||
height: $popover-arrow-height
|
||||
margin: 0 $border-radius-lg
|
||||
|
||||
&::before,
|
||||
&::after
|
||||
position: absolute
|
||||
display: block
|
||||
content: ""
|
||||
border-color: transparent
|
||||
border-style: solid
|
||||
|
||||
.bs-popover-top
|
||||
margin-bottom: $popover-arrow-height
|
||||
|
||||
.arrow
|
||||
bottom: calc((#{$popover-arrow-height} + #{$popover-border-width}) * -1)
|
||||
|
||||
.arrow::before,
|
||||
.arrow::after
|
||||
border-width: $popover-arrow-height ($popover-arrow-width / 2) 0
|
||||
|
||||
.arrow::before
|
||||
bottom: 0
|
||||
border-top-color: $popover-arrow-outer-color
|
||||
|
||||
.arrow::after
|
||||
bottom: $popover-border-width
|
||||
border-top-color: $popover-arrow-color
|
||||
|
||||
.bs-popover-right
|
||||
margin-left: $popover-arrow-height
|
||||
|
||||
.arrow
|
||||
left: calc((#{$popover-arrow-height} + #{$popover-border-width}) * -1)
|
||||
width: $popover-arrow-height
|
||||
height: $popover-arrow-width
|
||||
margin: $border-radius-lg 0
|
||||
|
||||
// make sure the arrow does not touch the popover's rounded corners
|
||||
|
||||
.arrow::before,
|
||||
.arrow::after
|
||||
border-width: ($popover-arrow-width / 2) $popover-arrow-height ($popover-arrow-width / 2) 0
|
||||
|
||||
.arrow::before
|
||||
left: 0
|
||||
border-right-color: $popover-arrow-outer-color
|
||||
|
||||
.arrow::after
|
||||
left: $popover-border-width
|
||||
border-right-color: $popover-arrow-color
|
||||
|
||||
.bs-popover-bottom
|
||||
margin-top: $popover-arrow-height
|
||||
|
||||
.arrow
|
||||
top: calc((#{$popover-arrow-height} + #{$popover-border-width}) * -1)
|
||||
|
||||
.arrow::before,
|
||||
.arrow::after
|
||||
border-width: 0 ($popover-arrow-width / 2) $popover-arrow-height ($popover-arrow-width / 2)
|
||||
|
||||
.arrow::before
|
||||
top: 0
|
||||
border-bottom-color: $popover-arrow-outer-color
|
||||
|
||||
.arrow::after
|
||||
top: $popover-border-width
|
||||
border-bottom-color: $popover-arrow-color
|
||||
|
||||
// This will remove the popover-header's border just below the arrow
|
||||
.popover-header::before
|
||||
position: absolute
|
||||
top: 0
|
||||
left: 50%
|
||||
display: block
|
||||
width: $popover-arrow-width
|
||||
margin-left: $popover-arrow-width / -2
|
||||
content: ""
|
||||
border-bottom: $popover-border-width solid $popover-header-bg
|
||||
|
||||
.bs-popover-left
|
||||
margin-right: $popover-arrow-height
|
||||
|
||||
.arrow
|
||||
right: calc((#{$popover-arrow-height} + #{$popover-border-width}) * -1)
|
||||
width: $popover-arrow-height
|
||||
height: $popover-arrow-width
|
||||
margin: $border-radius-lg 0
|
||||
|
||||
// make sure the arrow does not touch the popover's rounded corners
|
||||
|
||||
.arrow::before,
|
||||
.arrow::after
|
||||
border-width: ($popover-arrow-width / 2) 0 ($popover-arrow-width / 2) $popover-arrow-height
|
||||
|
||||
.arrow::before
|
||||
right: 0
|
||||
border-left-color: $popover-arrow-outer-color
|
||||
|
||||
.arrow::after
|
||||
right: $popover-border-width
|
||||
border-left-color: $popover-arrow-color
|
||||
|
||||
.bs-popover-auto
|
||||
&[x-placement^="top"]
|
||||
@extend .bs-popover-top
|
||||
|
||||
&[x-placement^="right"]
|
||||
@extend .bs-popover-right
|
||||
|
||||
&[x-placement^="bottom"]
|
||||
@extend .bs-popover-bottom
|
||||
|
||||
&[x-placement^="left"]
|
||||
@extend .bs-popover-left
|
||||
|
||||
// Offset the popover to account for the popover arrow
|
||||
.popover-header
|
||||
padding: $popover-header-padding-y $popover-header-padding-x
|
||||
margin-bottom: 0
|
||||
|
||||
// Reset the default from Reboot
|
||||
font-size: $font-size-base
|
||||
color: $popover-header-color
|
||||
background-color: $popover-header-bg
|
||||
border-bottom: $popover-border-width solid darken($popover-header-bg, 5%)
|
||||
|
||||
$offset-border-width: calc(#{$border-radius-lg} - #{$popover-border-width})
|
||||
|
||||
+border-top-radius($offset-border-width)
|
||||
|
||||
&:empty
|
||||
display: none
|
||||
|
||||
.popover-body
|
||||
padding: $popover-body-padding-y $popover-body-padding-x
|
||||
color: $popover-body-color
|
124
static/assets/bootstrap/sass/_print.sass
Normal file
124
static/assets/bootstrap/sass/_print.sass
Normal file
@@ -0,0 +1,124 @@
|
||||
// stylelint-disable declaration-no-important, selector-no-qualifying-type
|
||||
|
||||
// Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css
|
||||
|
||||
// ==========================================================================
|
||||
// Print styles.
|
||||
// Inlined to avoid the additional HTTP request:
|
||||
// https://www.phpied.com/delay-loading-your-print-css/
|
||||
// ==========================================================================
|
||||
|
||||
@if $enable-print-styles
|
||||
@media print
|
||||
*,
|
||||
*::before,
|
||||
*::after
|
||||
// Bootstrap specific; comment out `color` and `background`
|
||||
//color: $black !important; // Black prints faster
|
||||
text-shadow: none !important
|
||||
|
||||
//background: transparent !important;
|
||||
box-shadow: none !important
|
||||
|
||||
a
|
||||
&:not(.btn)
|
||||
text-decoration: underline
|
||||
|
||||
// Bootstrap specific; comment the following selector out
|
||||
//a[href]::after {
|
||||
// content: " (" attr(href) ")";
|
||||
//}
|
||||
|
||||
abbr[title]::after
|
||||
content: " (" attr(title) ")"
|
||||
|
||||
// Bootstrap specific; comment the following selector out
|
||||
//
|
||||
// Don't show links that are fragment identifiers,
|
||||
// or use the `javascript:` pseudo protocol
|
||||
//
|
||||
|
||||
//a[href^="#"]::after,
|
||||
//a[href^="javascript:"]::after {
|
||||
// content: "";
|
||||
//}
|
||||
|
||||
pre
|
||||
white-space: pre-wrap !important
|
||||
|
||||
pre,
|
||||
blockquote
|
||||
border: $border-width solid $gray-500
|
||||
|
||||
// Bootstrap custom code; using `$border-width` instead of 1px
|
||||
page-break-inside: avoid
|
||||
|
||||
//
|
||||
// Printing Tables:
|
||||
// http://css-discuss.incutio.com/wiki/Printing_Tables
|
||||
//
|
||||
|
||||
thead
|
||||
display: table-header-group
|
||||
|
||||
tr,
|
||||
img
|
||||
page-break-inside: avoid
|
||||
|
||||
p,
|
||||
h2,
|
||||
h3
|
||||
orphans: 3
|
||||
widows: 3
|
||||
|
||||
h2,
|
||||
h3
|
||||
page-break-after: avoid
|
||||
|
||||
// Bootstrap specific changes start
|
||||
|
||||
// Specify a size and min-width to make printing closer across browsers.
|
||||
// We don't set margin here because it breaks `size` in Chrome. We also
|
||||
// don't use `!important` on `size` as it breaks in Chrome.
|
||||
@page
|
||||
size: $print-page-size
|
||||
|
||||
body
|
||||
min-width: $print-body-min-width !important
|
||||
|
||||
.container
|
||||
min-width: $print-body-min-width !important
|
||||
|
||||
// Bootstrap components
|
||||
.navbar
|
||||
display: none
|
||||
|
||||
.badge
|
||||
border: $border-width solid $black
|
||||
|
||||
.table
|
||||
border-collapse: collapse !important
|
||||
|
||||
td,
|
||||
th
|
||||
background-color: $white !important
|
||||
|
||||
.table-bordered
|
||||
th,
|
||||
td
|
||||
border: 1px solid $gray-300 !important
|
||||
|
||||
.table-dark
|
||||
color: inherit
|
||||
|
||||
th,
|
||||
td,
|
||||
thead th,
|
||||
tbody + tbody
|
||||
border-color: $table-border-color
|
||||
|
||||
.table .thead-dark th
|
||||
color: inherit
|
||||
border-color: $table-border-color
|
||||
|
||||
// Bootstrap specific changes end
|
37
static/assets/bootstrap/sass/_progress.sass
Normal file
37
static/assets/bootstrap/sass/_progress.sass
Normal file
@@ -0,0 +1,37 @@
|
||||
@keyframes progress-bar-stripes
|
||||
from
|
||||
background-position: $progress-height 0
|
||||
|
||||
to
|
||||
background-position: 0 0
|
||||
|
||||
.progress
|
||||
display: flex
|
||||
height: $progress-height
|
||||
overflow: hidden
|
||||
|
||||
// force rounded corners by cropping it
|
||||
font-size: $progress-font-size
|
||||
background-color: $progress-bg
|
||||
|
||||
+border-radius($progress-border-radius)
|
||||
+box-shadow($progress-box-shadow)
|
||||
|
||||
.progress-bar
|
||||
display: flex
|
||||
flex-direction: column
|
||||
justify-content: center
|
||||
color: $progress-bar-color
|
||||
text-align: center
|
||||
white-space: nowrap
|
||||
background-color: $progress-bar-bg
|
||||
|
||||
+transition($progress-bar-transition)
|
||||
|
||||
.progress-bar-striped
|
||||
+gradient-striped
|
||||
|
||||
background-size: $progress-height $progress-height
|
||||
|
||||
.progress-bar-animated
|
||||
animation: progress-bar-stripes $progress-bar-animation-timing
|
513
static/assets/bootstrap/sass/_reboot.sass
Normal file
513
static/assets/bootstrap/sass/_reboot.sass
Normal file
@@ -0,0 +1,513 @@
|
||||
// stylelint-disable at-rule-no-vendor-prefix, declaration-no-important, selector-no-qualifying-type, property-no-vendor-prefix
|
||||
|
||||
// Reboot
|
||||
//
|
||||
// Normalization of HTML elements, manually forked from Normalize.css to remove
|
||||
// styles targeting irrelevant browsers while applying new styles.
|
||||
//
|
||||
// Normalize is licensed MIT. https://github.com/necolas/normalize.css
|
||||
|
||||
// Document
|
||||
//
|
||||
// 1. Change from `box-sizing: content-box` so that `width` is not affected by `padding` or `border`.
|
||||
// 2. Change the default font family in all browsers.
|
||||
// 3. Correct the line height in all browsers.
|
||||
// 4. Prevent adjustments of font size after orientation changes in IE on Windows Phone and in iOS.
|
||||
// 5. Setting @viewport causes scrollbars to overlap content in IE11 and Edge, so
|
||||
// we force a non-overlapping, non-auto-hiding scrollbar to counteract.
|
||||
// 6. Change the default tap highlight to be completely transparent in iOS.
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after
|
||||
box-sizing: border-box
|
||||
|
||||
// 1
|
||||
|
||||
html
|
||||
font-family: sans-serif
|
||||
|
||||
// 2
|
||||
line-height: 1.15
|
||||
|
||||
// 3
|
||||
-webkit-text-size-adjust: 100%
|
||||
|
||||
// 4
|
||||
-ms-text-size-adjust: 100%
|
||||
|
||||
// 4
|
||||
-ms-overflow-style: scrollbar
|
||||
|
||||
// 5
|
||||
-webkit-tap-highlight-color: rgba($black, 0)
|
||||
|
||||
// 6
|
||||
|
||||
// IE10+ doesn't honor `<meta name="viewport">` in some cases.
|
||||
@at-root
|
||||
@-ms-viewport
|
||||
width: device-width
|
||||
|
||||
// stylelint-disable selector-list-comma-newline-after
|
||||
// Shim for "new" HTML5 structural elements to display correctly (IE10, older browsers)
|
||||
article, aside, figcaption, figure, footer, header, hgroup, main, nav, section
|
||||
display: block
|
||||
|
||||
// stylelint-enable selector-list-comma-newline-after
|
||||
|
||||
// Body
|
||||
//
|
||||
// 1. Remove the margin in all browsers.
|
||||
// 2. As a best practice, apply a default `background-color`.
|
||||
// 3. Set an explicit initial text-align value so that we can later use the
|
||||
// the `inherit` value on things like `<th>` elements.
|
||||
|
||||
body
|
||||
margin: 0
|
||||
|
||||
// 1
|
||||
font-family: $font-family-base
|
||||
font-size: $font-size-base
|
||||
font-weight: $font-weight-base
|
||||
line-height: $line-height-base
|
||||
color: $body-color
|
||||
text-align: left
|
||||
|
||||
// 3
|
||||
background-color: $body-bg
|
||||
|
||||
// 2
|
||||
|
||||
// Suppress the focus outline on elements that cannot be accessed via keyboard.
|
||||
// This prevents an unwanted focus outline from appearing around elements that
|
||||
// might still respond to pointer events.
|
||||
//
|
||||
// Credit: https://github.com/suitcss/base
|
||||
[tabindex="-1"]:focus
|
||||
outline: 0 !important
|
||||
|
||||
// Content grouping
|
||||
//
|
||||
// 1. Add the correct box sizing in Firefox.
|
||||
// 2. Show the overflow in Edge and IE.
|
||||
|
||||
hr
|
||||
box-sizing: content-box
|
||||
|
||||
// 1
|
||||
height: 0
|
||||
|
||||
// 1
|
||||
overflow: visible
|
||||
|
||||
// 2
|
||||
|
||||
//
|
||||
// Typography
|
||||
//
|
||||
|
||||
// Remove top margins from headings
|
||||
//
|
||||
// By default, `<h1>`-`<h6>` all receive top and bottom margins. We nuke the top
|
||||
// margin for easier control within type scales as it avoids margin collapsing.
|
||||
// stylelint-disable selector-list-comma-newline-after
|
||||
h1, h2, h3, h4, h5, h6
|
||||
margin-top: 0
|
||||
margin-bottom: $headings-margin-bottom
|
||||
|
||||
// stylelint-enable selector-list-comma-newline-after
|
||||
|
||||
// Reset margins on paragraphs
|
||||
//
|
||||
// Similarly, the top margin on `<p>`s get reset. However, we also reset the
|
||||
// bottom margin to use `rem` units instead of `em`.
|
||||
p
|
||||
margin-top: 0
|
||||
margin-bottom: $paragraph-margin-bottom
|
||||
|
||||
// Abbreviations
|
||||
//
|
||||
// 1. Remove the bottom border in Firefox 39-.
|
||||
// 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
|
||||
// 3. Add explicit cursor to indicate changed behavior.
|
||||
// 4. Duplicate behavior to the data-* attribute for our tooltip plugin
|
||||
|
||||
abbr[title],
|
||||
abbr[data-original-title]
|
||||
// 4
|
||||
text-decoration: underline
|
||||
|
||||
// 2
|
||||
text-decoration: underline dotted
|
||||
|
||||
// 2
|
||||
cursor: help
|
||||
|
||||
// 3
|
||||
border-bottom: 0
|
||||
|
||||
// 1
|
||||
|
||||
address
|
||||
margin-bottom: 1rem
|
||||
font-style: normal
|
||||
line-height: inherit
|
||||
|
||||
ol,
|
||||
ul,
|
||||
dl
|
||||
margin-top: 0
|
||||
margin-bottom: 1rem
|
||||
|
||||
ol ol,
|
||||
ul ul,
|
||||
ol ul,
|
||||
ul ol
|
||||
margin-bottom: 0
|
||||
|
||||
dt
|
||||
font-weight: $dt-font-weight
|
||||
|
||||
dd
|
||||
margin-bottom: .5rem
|
||||
margin-left: 0
|
||||
|
||||
// Undo browser default
|
||||
|
||||
blockquote
|
||||
margin: 0 0 1rem
|
||||
|
||||
dfn
|
||||
font-style: italic
|
||||
|
||||
// Add the correct font style in Android 4.3-
|
||||
|
||||
// stylelint-disable font-weight-notation
|
||||
b,
|
||||
strong
|
||||
font-weight: bolder
|
||||
|
||||
// Add the correct font weight in Chrome, Edge, and Safari
|
||||
|
||||
// stylelint-enable font-weight-notation
|
||||
|
||||
small
|
||||
font-size: 80%
|
||||
|
||||
// Add the correct font size in all browsers
|
||||
|
||||
//
|
||||
// Prevent `sub` and `sup` elements from affecting the line height in
|
||||
// all browsers.
|
||||
//
|
||||
|
||||
sub,
|
||||
sup
|
||||
position: relative
|
||||
font-size: 75%
|
||||
line-height: 0
|
||||
vertical-align: baseline
|
||||
|
||||
sub
|
||||
bottom: -.25em
|
||||
|
||||
sup
|
||||
top: -.5em
|
||||
|
||||
//
|
||||
// Links
|
||||
//
|
||||
|
||||
a
|
||||
color: $link-color
|
||||
text-decoration: $link-decoration
|
||||
background-color: transparent
|
||||
|
||||
// Remove the gray background on active links in IE 10.
|
||||
-webkit-text-decoration-skip: objects
|
||||
|
||||
// Remove gaps in links underline in iOS 8+ and Safari 8+.
|
||||
|
||||
+hover
|
||||
color: $link-hover-color
|
||||
text-decoration: $link-hover-decoration
|
||||
|
||||
// And undo these styles for placeholder links/named anchors (without href)
|
||||
// which have not been made explicitly keyboard-focusable (without tabindex).
|
||||
// It would be more straightforward to just use a[href] in previous block, but that
|
||||
// causes specificity issues in many other styles that are too complex to fix.
|
||||
// See https://github.com/twbs/bootstrap/issues/19402
|
||||
|
||||
a:not([href]):not([tabindex])
|
||||
color: inherit
|
||||
text-decoration: none
|
||||
|
||||
+hover-focus
|
||||
color: inherit
|
||||
text-decoration: none
|
||||
|
||||
|
||||
&:focus
|
||||
outline: 0
|
||||
|
||||
//
|
||||
// Code
|
||||
//
|
||||
|
||||
pre,
|
||||
code,
|
||||
kbd,
|
||||
samp
|
||||
font-family: $font-family-monospace
|
||||
font-size: 1em
|
||||
|
||||
// Correct the odd `em` font sizing in all browsers.
|
||||
|
||||
pre
|
||||
// Remove browser default top margin
|
||||
margin-top: 0
|
||||
|
||||
// Reset browser default of `1em` to use `rem`s
|
||||
margin-bottom: 1rem
|
||||
|
||||
// Don't allow content to break outside
|
||||
overflow: auto
|
||||
|
||||
// We have @viewport set which causes scrollbars to overlap content in IE11 and Edge, so
|
||||
// we force a non-overlapping, non-auto-hiding scrollbar to counteract.
|
||||
-ms-overflow-style: scrollbar
|
||||
|
||||
//
|
||||
// Figures
|
||||
//
|
||||
|
||||
figure
|
||||
// Apply a consistent margin strategy (matches our type styles).
|
||||
margin: 0 0 1rem
|
||||
|
||||
//
|
||||
// Images and content
|
||||
//
|
||||
|
||||
img
|
||||
vertical-align: middle
|
||||
border-style: none
|
||||
|
||||
// Remove the border on images inside links in IE 10-.
|
||||
|
||||
svg:not(:root)
|
||||
overflow: hidden
|
||||
|
||||
// Hide the overflow in IE
|
||||
vertical-align: middle
|
||||
|
||||
//
|
||||
// Tables
|
||||
//
|
||||
|
||||
table
|
||||
border-collapse: collapse
|
||||
|
||||
// Prevent double borders
|
||||
|
||||
caption
|
||||
padding-top: $table-cell-padding
|
||||
padding-bottom: $table-cell-padding
|
||||
color: $table-caption-color
|
||||
text-align: left
|
||||
caption-side: bottom
|
||||
|
||||
th
|
||||
// Matches default `<td>` alignment by inheriting from the `<body>`, or the
|
||||
// closest parent with a set `text-align`.
|
||||
text-align: inherit
|
||||
|
||||
//
|
||||
// Forms
|
||||
//
|
||||
|
||||
label
|
||||
// Allow labels to use `margin` for spacing.
|
||||
display: inline-block
|
||||
margin-bottom: $label-margin-bottom
|
||||
|
||||
// Remove the default `border-radius` that macOS Chrome adds.
|
||||
//
|
||||
// Details at https://github.com/twbs/bootstrap/issues/24093
|
||||
button
|
||||
border-radius: 0
|
||||
|
||||
// Work around a Firefox/IE bug where the transparent `button` background
|
||||
// results in a loss of the default `button` focus styles.
|
||||
//
|
||||
// Credit: https://github.com/suitcss/base/
|
||||
button:focus
|
||||
outline: 1px dotted
|
||||
outline: 5px auto -webkit-focus-ring-color
|
||||
|
||||
input,
|
||||
button,
|
||||
select,
|
||||
optgroup,
|
||||
textarea
|
||||
margin: 0
|
||||
|
||||
// Remove the margin in Firefox and Safari
|
||||
font-family: inherit
|
||||
font-size: inherit
|
||||
line-height: inherit
|
||||
|
||||
button,
|
||||
input
|
||||
overflow: visible
|
||||
|
||||
// Show the overflow in Edge
|
||||
|
||||
button,
|
||||
select
|
||||
text-transform: none
|
||||
|
||||
// Remove the inheritance of text transform in Firefox
|
||||
|
||||
// 1. Prevent a WebKit bug where (2) destroys native `audio` and `video`
|
||||
// controls in Android 4.
|
||||
// 2. Correct the inability to style clickable types in iOS and Safari.
|
||||
button,
|
||||
html [type="button"],
|
||||
[type="reset"],
|
||||
[type="submit"]
|
||||
-webkit-appearance: button
|
||||
|
||||
// 2
|
||||
|
||||
// Remove inner border and padding from Firefox, but don't restore the outline like Normalize.
|
||||
button::-moz-focus-inner,
|
||||
[type="button"]::-moz-focus-inner,
|
||||
[type="reset"]::-moz-focus-inner,
|
||||
[type="submit"]::-moz-focus-inner
|
||||
padding: 0
|
||||
border-style: none
|
||||
|
||||
input[type="radio"],
|
||||
input[type="checkbox"]
|
||||
box-sizing: border-box
|
||||
|
||||
// 1. Add the correct box sizing in IE 10-
|
||||
padding: 0
|
||||
|
||||
// 2. Remove the padding in IE 10-
|
||||
|
||||
input[type="date"],
|
||||
input[type="time"],
|
||||
input[type="datetime-local"],
|
||||
input[type="month"]
|
||||
// Remove the default appearance of temporal inputs to avoid a Mobile Safari
|
||||
// bug where setting a custom line-height prevents text from being vertically
|
||||
// centered within the input.
|
||||
// See https://bugs.webkit.org/show_bug.cgi?id=139848
|
||||
// and https://github.com/twbs/bootstrap/issues/11266
|
||||
-webkit-appearance: listbox
|
||||
|
||||
textarea
|
||||
overflow: auto
|
||||
|
||||
// Remove the default vertical scrollbar in IE.
|
||||
// Textareas should really only resize vertically so they don't break their (horizontal) containers.
|
||||
resize: vertical
|
||||
|
||||
fieldset
|
||||
// Browsers set a default `min-width: min-content;` on fieldsets,
|
||||
// unlike e.g. `<div>`s, which have `min-width: 0;` by default.
|
||||
// So we reset that to ensure fieldsets behave more like a standard block element.
|
||||
// See https://github.com/twbs/bootstrap/issues/12359
|
||||
// and https://html.spec.whatwg.org/multipage/#the-fieldset-and-legend-elements
|
||||
min-width: 0
|
||||
|
||||
// Reset the default outline behavior of fieldsets so they don't affect page layout.
|
||||
padding: 0
|
||||
margin: 0
|
||||
border: 0
|
||||
|
||||
// 1. Correct the text wrapping in Edge and IE.
|
||||
// 2. Correct the color inheritance from `fieldset` elements in IE.
|
||||
legend
|
||||
display: block
|
||||
width: 100%
|
||||
max-width: 100%
|
||||
|
||||
// 1
|
||||
padding: 0
|
||||
margin-bottom: .5rem
|
||||
font-size: 1.5rem
|
||||
line-height: inherit
|
||||
color: inherit
|
||||
|
||||
// 2
|
||||
white-space: normal
|
||||
|
||||
// 1
|
||||
|
||||
progress
|
||||
vertical-align: baseline
|
||||
|
||||
// Add the correct vertical alignment in Chrome, Firefox, and Opera.
|
||||
|
||||
// Correct the cursor style of increment and decrement buttons in Chrome.
|
||||
[type="number"]::-webkit-inner-spin-button,
|
||||
[type="number"]::-webkit-outer-spin-button
|
||||
height: auto
|
||||
|
||||
[type="search"]
|
||||
// This overrides the extra rounded corners on search inputs in iOS so that our
|
||||
// `.form-control` class can properly style them. Note that this cannot simply
|
||||
// be added to `.form-control` as it's not specific enough. For details, see
|
||||
// https://github.com/twbs/bootstrap/issues/11586.
|
||||
outline-offset: -2px
|
||||
|
||||
// 2. Correct the outline style in Safari.
|
||||
-webkit-appearance: none
|
||||
|
||||
//
|
||||
// Remove the inner padding and cancel buttons in Chrome and Safari on macOS.
|
||||
//
|
||||
|
||||
[type="search"]::-webkit-search-cancel-button,
|
||||
[type="search"]::-webkit-search-decoration
|
||||
-webkit-appearance: none
|
||||
|
||||
//
|
||||
// 1. Correct the inability to style clickable types in iOS and Safari.
|
||||
// 2. Change font properties to `inherit` in Safari.
|
||||
//
|
||||
|
||||
\::-webkit-file-upload-button
|
||||
font: inherit
|
||||
|
||||
// 2
|
||||
-webkit-appearance: button
|
||||
|
||||
// 1
|
||||
|
||||
//
|
||||
// Correct element displays
|
||||
//
|
||||
|
||||
output
|
||||
display: inline-block
|
||||
|
||||
summary
|
||||
display: list-item
|
||||
|
||||
// Add the correct display in all browsers
|
||||
cursor: pointer
|
||||
|
||||
template
|
||||
display: none
|
||||
|
||||
// Add the correct display in IE
|
||||
|
||||
// Always hide an element with the `hidden` HTML attribute (from PureCSS).
|
||||
// Needed for proper display in IE 10-.
|
||||
[hidden]
|
||||
display: none !important
|
15
static/assets/bootstrap/sass/_root.sass
Normal file
15
static/assets/bootstrap/sass/_root.sass
Normal file
@@ -0,0 +1,15 @@
|
||||
\:root
|
||||
// Custom variable values only support SassScript inside `#{}`.
|
||||
@each $color, $value in $colors
|
||||
--#{$color}: #{$value}
|
||||
|
||||
@each $color, $value in $theme-colors
|
||||
--#{$color}: #{$value}
|
||||
|
||||
@each $bp, $value in $grid-breakpoints
|
||||
--breakpoint-#{$bp}: #{$value}
|
||||
|
||||
// Use `inspect` for lists so that quoted items keep the quotes.
|
||||
// See https://github.com/sass/sass/issues/2383#issuecomment-336349172
|
||||
--font-family-sans-serif: #{inspect($font-family-sans-serif)}
|
||||
--font-family-monospace: #{inspect($font-family-monospace)}
|
149
static/assets/bootstrap/sass/_tables.sass
Normal file
149
static/assets/bootstrap/sass/_tables.sass
Normal file
@@ -0,0 +1,149 @@
|
||||
//
|
||||
// Basic Bootstrap table
|
||||
//
|
||||
|
||||
.table
|
||||
width: 100%
|
||||
max-width: 100%
|
||||
margin-bottom: $spacer
|
||||
background-color: $table-bg
|
||||
|
||||
// Reset for nesting within parents with `background-color`.
|
||||
|
||||
th,
|
||||
td
|
||||
padding: $table-cell-padding
|
||||
vertical-align: top
|
||||
border-top: $table-border-width solid $table-border-color
|
||||
|
||||
thead th
|
||||
vertical-align: bottom
|
||||
border-bottom: (2 * $table-border-width) solid $table-border-color
|
||||
|
||||
tbody + tbody
|
||||
border-top: (2 * $table-border-width) solid $table-border-color
|
||||
|
||||
.table
|
||||
background-color: $body-bg
|
||||
|
||||
//
|
||||
// Condensed table w/ half padding
|
||||
//
|
||||
|
||||
.table-sm
|
||||
th,
|
||||
td
|
||||
padding: $table-cell-padding-sm
|
||||
|
||||
// Border versions
|
||||
//
|
||||
// Add or remove borders all around the table and between all the columns.
|
||||
|
||||
.table-bordered
|
||||
border: $table-border-width solid $table-border-color
|
||||
|
||||
th,
|
||||
td
|
||||
border: $table-border-width solid $table-border-color
|
||||
|
||||
thead
|
||||
th,
|
||||
td
|
||||
border-bottom-width: 2 * $table-border-width
|
||||
|
||||
.table-borderless
|
||||
th,
|
||||
td,
|
||||
thead th,
|
||||
tbody + tbody
|
||||
border: 0
|
||||
|
||||
// Zebra-striping
|
||||
//
|
||||
// Default zebra-stripe styles (alternating gray and transparent backgrounds)
|
||||
|
||||
.table-striped
|
||||
tbody tr:nth-of-type(#{$table-striped-order})
|
||||
background-color: $table-accent-bg
|
||||
|
||||
// Hover effect
|
||||
//
|
||||
// Placed here since it has to come after the potential zebra striping
|
||||
|
||||
.table-hover
|
||||
tbody tr
|
||||
+hover
|
||||
background-color: $table-hover-bg
|
||||
|
||||
// Table backgrounds
|
||||
//
|
||||
// Exact selectors below required to override `.table-striped` and prevent
|
||||
// inheritance to nested tables.
|
||||
|
||||
@each $color, $value in $theme-colors
|
||||
+table-row-variant($color, theme-color-level($color, -9))
|
||||
|
||||
+table-row-variant(active, $table-active-bg)
|
||||
|
||||
// Dark styles
|
||||
//
|
||||
// Same table markup, but inverted color scheme: dark background and light text.
|
||||
|
||||
// stylelint-disable-next-line no-duplicate-selectors
|
||||
.table
|
||||
.thead-dark
|
||||
th
|
||||
color: $table-dark-color
|
||||
background-color: $table-dark-bg
|
||||
border-color: $table-dark-border-color
|
||||
|
||||
.thead-light
|
||||
th
|
||||
color: $table-head-color
|
||||
background-color: $table-head-bg
|
||||
border-color: $table-border-color
|
||||
|
||||
.table-dark
|
||||
color: $table-dark-color
|
||||
background-color: $table-dark-bg
|
||||
|
||||
th,
|
||||
td,
|
||||
thead th
|
||||
border-color: $table-dark-border-color
|
||||
|
||||
&.table-bordered
|
||||
border: 0
|
||||
|
||||
&.table-striped
|
||||
tbody tr:nth-of-type(odd)
|
||||
background-color: $table-dark-accent-bg
|
||||
|
||||
&.table-hover
|
||||
tbody tr
|
||||
+hover
|
||||
background-color: $table-dark-hover-bg
|
||||
|
||||
// Responsive tables
|
||||
//
|
||||
// Generate series of `.table-responsive-*` classes for configuring the screen
|
||||
// size of where your table will overflow.
|
||||
|
||||
.table-responsive
|
||||
@each $breakpoint in map-keys($grid-breakpoints)
|
||||
$next: breakpoint-next($breakpoint, $grid-breakpoints)
|
||||
$infix: breakpoint-infix($next, $grid-breakpoints)
|
||||
|
||||
&#{$infix}
|
||||
+media-breakpoint-down($breakpoint)
|
||||
display: block
|
||||
width: 100%
|
||||
overflow-x: auto
|
||||
-webkit-overflow-scrolling: touch
|
||||
-ms-overflow-style: -ms-autohiding-scrollbar
|
||||
|
||||
// See https://github.com/twbs/bootstrap/pull/10057
|
||||
|
||||
// Prevent double border on horizontal scroll due to use of `display: block;`
|
||||
> .table-bordered
|
||||
border: 0
|
102
static/assets/bootstrap/sass/_tooltip.sass
Normal file
102
static/assets/bootstrap/sass/_tooltip.sass
Normal file
@@ -0,0 +1,102 @@
|
||||
// Base class
|
||||
.tooltip
|
||||
position: absolute
|
||||
z-index: $zindex-tooltip
|
||||
display: block
|
||||
margin: $tooltip-margin
|
||||
|
||||
// Our parent element can be arbitrary since tooltips are by default inserted as a sibling of their target element.
|
||||
// So reset our font and text properties to avoid inheriting weird values.
|
||||
+reset-text
|
||||
|
||||
font-size: $tooltip-font-size
|
||||
|
||||
// Allow breaking very long words so they don't overflow the tooltip's bounds
|
||||
word-wrap: break-word
|
||||
opacity: 0
|
||||
|
||||
&.show
|
||||
opacity: $tooltip-opacity
|
||||
|
||||
.arrow
|
||||
position: absolute
|
||||
display: block
|
||||
width: $tooltip-arrow-width
|
||||
height: $tooltip-arrow-height
|
||||
|
||||
&::before
|
||||
position: absolute
|
||||
content: ""
|
||||
border-color: transparent
|
||||
border-style: solid
|
||||
|
||||
.bs-tooltip-top
|
||||
padding: $tooltip-arrow-height 0
|
||||
|
||||
.arrow
|
||||
bottom: 0
|
||||
|
||||
&::before
|
||||
top: 0
|
||||
border-width: $tooltip-arrow-height ($tooltip-arrow-width / 2) 0
|
||||
border-top-color: $tooltip-arrow-color
|
||||
|
||||
.bs-tooltip-right
|
||||
padding: 0 $tooltip-arrow-height
|
||||
|
||||
.arrow
|
||||
left: 0
|
||||
width: $tooltip-arrow-height
|
||||
height: $tooltip-arrow-width
|
||||
|
||||
&::before
|
||||
right: 0
|
||||
border-width: ($tooltip-arrow-width / 2) $tooltip-arrow-height ($tooltip-arrow-width / 2) 0
|
||||
border-right-color: $tooltip-arrow-color
|
||||
|
||||
.bs-tooltip-bottom
|
||||
padding: $tooltip-arrow-height 0
|
||||
|
||||
.arrow
|
||||
top: 0
|
||||
|
||||
&::before
|
||||
bottom: 0
|
||||
border-width: 0 ($tooltip-arrow-width / 2) $tooltip-arrow-height
|
||||
border-bottom-color: $tooltip-arrow-color
|
||||
|
||||
.bs-tooltip-left
|
||||
padding: 0 $tooltip-arrow-height
|
||||
|
||||
.arrow
|
||||
right: 0
|
||||
width: $tooltip-arrow-height
|
||||
height: $tooltip-arrow-width
|
||||
|
||||
&::before
|
||||
left: 0
|
||||
border-width: ($tooltip-arrow-width / 2) 0 ($tooltip-arrow-width / 2) $tooltip-arrow-height
|
||||
border-left-color: $tooltip-arrow-color
|
||||
|
||||
.bs-tooltip-auto
|
||||
&[x-placement^="top"]
|
||||
@extend .bs-tooltip-top
|
||||
|
||||
&[x-placement^="right"]
|
||||
@extend .bs-tooltip-right
|
||||
|
||||
&[x-placement^="bottom"]
|
||||
@extend .bs-tooltip-bottom
|
||||
|
||||
&[x-placement^="left"]
|
||||
@extend .bs-tooltip-left
|
||||
|
||||
// Wrapper for the tooltip content
|
||||
.tooltip-inner
|
||||
max-width: $tooltip-max-width
|
||||
padding: $tooltip-padding-y $tooltip-padding-x
|
||||
color: $tooltip-color
|
||||
text-align: center
|
||||
background-color: $tooltip-bg
|
||||
|
||||
+border-radius($tooltip-border-radius)
|
18
static/assets/bootstrap/sass/_transitions.sass
Normal file
18
static/assets/bootstrap/sass/_transitions.sass
Normal file
@@ -0,0 +1,18 @@
|
||||
// stylelint-disable selector-no-qualifying-type
|
||||
|
||||
.fade
|
||||
+transition($transition-fade)
|
||||
|
||||
&:not(.show)
|
||||
opacity: 0
|
||||
|
||||
.collapse
|
||||
&:not(.show)
|
||||
display: none
|
||||
|
||||
.collapsing
|
||||
position: relative
|
||||
height: 0
|
||||
overflow: hidden
|
||||
|
||||
+transition($transition-collapse)
|
123
static/assets/bootstrap/sass/_type.sass
Normal file
123
static/assets/bootstrap/sass/_type.sass
Normal file
@@ -0,0 +1,123 @@
|
||||
// stylelint-disable declaration-no-important, selector-list-comma-newline-after
|
||||
|
||||
//
|
||||
// Headings
|
||||
//
|
||||
|
||||
h1, h2, h3, h4, h5, h6,
|
||||
.h1, .h2, .h3, .h4, .h5, .h6
|
||||
margin-bottom: $headings-margin-bottom
|
||||
font-family: $headings-font-family
|
||||
font-weight: $headings-font-weight
|
||||
line-height: $headings-line-height
|
||||
color: $headings-color
|
||||
|
||||
h1, .h1
|
||||
font-size: $h1-font-size
|
||||
|
||||
h2, .h2
|
||||
font-size: $h2-font-size
|
||||
|
||||
h3, .h3
|
||||
font-size: $h3-font-size
|
||||
|
||||
h4, .h4
|
||||
font-size: $h4-font-size
|
||||
|
||||
h5, .h5
|
||||
font-size: $h5-font-size
|
||||
|
||||
h6, .h6
|
||||
font-size: $h6-font-size
|
||||
|
||||
.lead
|
||||
font-size: $lead-font-size
|
||||
font-weight: $lead-font-weight
|
||||
|
||||
// Type display classes
|
||||
.display-1
|
||||
font-size: $display1-size
|
||||
font-weight: $display1-weight
|
||||
line-height: $display-line-height
|
||||
|
||||
.display-2
|
||||
font-size: $display2-size
|
||||
font-weight: $display2-weight
|
||||
line-height: $display-line-height
|
||||
|
||||
.display-3
|
||||
font-size: $display3-size
|
||||
font-weight: $display3-weight
|
||||
line-height: $display-line-height
|
||||
|
||||
.display-4
|
||||
font-size: $display4-size
|
||||
font-weight: $display4-weight
|
||||
line-height: $display-line-height
|
||||
|
||||
//
|
||||
// Horizontal rules
|
||||
//
|
||||
|
||||
hr
|
||||
margin-top: $hr-margin-y
|
||||
margin-bottom: $hr-margin-y
|
||||
border: 0
|
||||
border-top: $hr-border-width solid $hr-border-color
|
||||
|
||||
//
|
||||
// Emphasis
|
||||
//
|
||||
|
||||
small,
|
||||
.small
|
||||
font-size: $small-font-size
|
||||
font-weight: $font-weight-normal
|
||||
|
||||
mark,
|
||||
.mark
|
||||
padding: $mark-padding
|
||||
background-color: $mark-bg
|
||||
|
||||
//
|
||||
// Lists
|
||||
//
|
||||
|
||||
.list-unstyled
|
||||
+list-unstyled
|
||||
|
||||
// Inline turns list items into inline-block
|
||||
.list-inline
|
||||
+list-unstyled
|
||||
|
||||
.list-inline-item
|
||||
display: inline-block
|
||||
|
||||
&:not(:last-child)
|
||||
margin-right: $list-inline-padding
|
||||
|
||||
//
|
||||
// Misc
|
||||
//
|
||||
|
||||
// Builds on `abbr`
|
||||
.initialism
|
||||
font-size: 90%
|
||||
text-transform: uppercase
|
||||
|
||||
// Blockquotes
|
||||
.blockquote
|
||||
margin-bottom: $spacer
|
||||
font-size: $blockquote-font-size
|
||||
|
||||
.blockquote-footer
|
||||
display: block
|
||||
font-size: 80%
|
||||
|
||||
// back to default font-size
|
||||
color: $blockquote-small-color
|
||||
|
||||
&::before
|
||||
content: "\2014 \00A0"
|
||||
|
||||
// em dash, nbsp
|
15
static/assets/bootstrap/sass/_utilities.sass
Normal file
15
static/assets/bootstrap/sass/_utilities.sass
Normal file
@@ -0,0 +1,15 @@
|
||||
@import utilities/align
|
||||
@import utilities/background
|
||||
@import utilities/borders
|
||||
@import utilities/clearfix
|
||||
@import utilities/display
|
||||
@import utilities/embed
|
||||
@import utilities/flex
|
||||
@import utilities/float
|
||||
@import utilities/position
|
||||
@import utilities/screenreaders
|
||||
@import utilities/shadows
|
||||
@import utilities/sizing
|
||||
@import utilities/spacing
|
||||
@import utilities/text
|
||||
@import utilities/visibility
|
868
static/assets/bootstrap/sass/_variables.sass
Normal file
868
static/assets/bootstrap/sass/_variables.sass
Normal file
@@ -0,0 +1,868 @@
|
||||
// Variables
|
||||
//
|
||||
// Variables should follow the `$component-state-property-size` formula for
|
||||
// consistent naming. Ex: $nav-link-disabled-color and $modal-content-box-shadow-xs.
|
||||
|
||||
//
|
||||
// Color system
|
||||
//
|
||||
|
||||
$white: #fff !default
|
||||
$gray-100: #f8f9fa !default
|
||||
$gray-200: #e9ecef !default
|
||||
$gray-300: #dee2e6 !default
|
||||
$gray-400: #ced4da !default
|
||||
$gray-500: #adb5bd !default
|
||||
$gray-600: #6c757d !default
|
||||
$gray-700: #495057 !default
|
||||
$gray-800: #343a40 !default
|
||||
$gray-900: #212529 !default
|
||||
$black: #000 !default
|
||||
|
||||
$grays: () !default
|
||||
|
||||
// stylelint-disable-next-line scss/dollar-variable-default
|
||||
$grays: map-merge(("100": $gray-100, "200": $gray-200, "300": $gray-300, "400": $gray-400, "500": $gray-500, "600": $gray-600, "700": $gray-700, "800": $gray-800, "900": $gray-900), $grays)
|
||||
|
||||
$blue: #007bff !default
|
||||
$indigo: #6610f2 !default
|
||||
$purple: #6f42c1 !default
|
||||
$pink: #e83e8c !default
|
||||
$red: #dc3545 !default
|
||||
$orange: #fd7e14 !default
|
||||
$yellow: #ffc107 !default
|
||||
$green: #28a745 !default
|
||||
$teal: #20c997 !default
|
||||
$cyan: #17a2b8 !default
|
||||
|
||||
$colors: () !default
|
||||
|
||||
// stylelint-disable-next-line scss/dollar-variable-default
|
||||
$colors: map-merge(("blue": $blue, "indigo": $indigo, "purple": $purple, "pink": $pink, "red": $red, "orange": $orange, "yellow": $yellow, "green": $green, "teal": $teal, "cyan": $cyan, "white": $white, "gray": $gray-600, "gray-dark": $gray-800), $colors)
|
||||
|
||||
$primary: $blue !default
|
||||
$secondary: $gray-600 !default
|
||||
$success: $green !default
|
||||
$info: $cyan !default
|
||||
$warning: $yellow !default
|
||||
$danger: $red !default
|
||||
$light: $gray-100 !default
|
||||
$dark: $gray-800 !default
|
||||
|
||||
$theme-colors: () !default
|
||||
|
||||
// stylelint-disable-next-line scss/dollar-variable-default
|
||||
$theme-colors: map-merge(("primary": $primary, "secondary": $secondary, "success": $success, "info": $info, "warning": $warning, "danger": $danger, "light": $light, "dark": $dark), $theme-colors)
|
||||
|
||||
// Set a specific jump point for requesting color jumps
|
||||
$theme-color-interval: 8% !default
|
||||
|
||||
// The yiq lightness value that determines when the lightness of color changes from "dark" to "light". Acceptable values are between 0 and 255.
|
||||
$yiq-contrasted-threshold: 150 !default
|
||||
|
||||
// Customize the light and dark text colors for use in our YIQ color contrast function.
|
||||
$yiq-text-dark: $gray-900 !default
|
||||
$yiq-text-light: $white !default
|
||||
|
||||
// Options
|
||||
//
|
||||
// Quickly modify global styling by enabling or disabling optional features.
|
||||
|
||||
$enable-caret: true !default
|
||||
$enable-rounded: true !default
|
||||
$enable-shadows: false !default
|
||||
$enable-gradients: false !default
|
||||
$enable-transitions: true !default
|
||||
$enable-hover-media-query: false !default
|
||||
|
||||
// Deprecated, no longer affects any compiled CSS
|
||||
$enable-grid-classes: true !default
|
||||
$enable-print-styles: true !default
|
||||
|
||||
// Spacing
|
||||
//
|
||||
// Control the default styling of most Bootstrap elements by modifying these
|
||||
// variables. Mostly focused on spacing.
|
||||
// You can add more entries to the $spacers map, should you need more variation.
|
||||
|
||||
$spacer: 1rem !default
|
||||
$spacers: () !default
|
||||
|
||||
// stylelint-disable-next-line scss/dollar-variable-default
|
||||
$spacers: map-merge((0: 0, 1: $spacer * 0.25, 2: $spacer * 0.5, 3: $spacer, 4: $spacer * 1.5, 5: $spacer * 3), $spacers)
|
||||
|
||||
// This variable affects the `.h-*` and `.w-*` classes.
|
||||
$sizes: () !default
|
||||
|
||||
// stylelint-disable-next-line scss/dollar-variable-default
|
||||
$sizes: map-merge((25: 25%, 50: 50%, 75: 75%, 100: 100%, auto: auto), $sizes)
|
||||
|
||||
// Body
|
||||
//
|
||||
// Settings for the `<body>` element.
|
||||
|
||||
$body-bg: $white !default
|
||||
$body-color: $gray-900 !default
|
||||
|
||||
// Links
|
||||
//
|
||||
// Style anchor elements.
|
||||
|
||||
$link-color: theme-color("primary") !default
|
||||
$link-decoration: none !default
|
||||
$link-hover-color: darken($link-color, 15%) !default
|
||||
$link-hover-decoration: underline !default
|
||||
|
||||
// Paragraphs
|
||||
//
|
||||
// Style p element.
|
||||
|
||||
$paragraph-margin-bottom: 1rem !default
|
||||
|
||||
// Grid breakpoints
|
||||
//
|
||||
// Define the minimum dimensions at which your layout will change,
|
||||
// adapting to different screen sizes, for use in media queries.
|
||||
|
||||
$grid-breakpoints: (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px) !default
|
||||
|
||||
+_assert-ascending($grid-breakpoints, "$grid-breakpoints")
|
||||
+_assert-starts-at-zero($grid-breakpoints)
|
||||
|
||||
// Grid containers
|
||||
//
|
||||
// Define the maximum width of `.container` for different screen sizes.
|
||||
|
||||
$container-max-widths: (sm: 540px, md: 720px, lg: 960px, xl: 1140px) !default
|
||||
|
||||
+_assert-ascending($container-max-widths, "$container-max-widths")
|
||||
|
||||
// Grid columns
|
||||
//
|
||||
// Set the number of columns and specify the width of the gutters.
|
||||
|
||||
$grid-columns: 12 !default
|
||||
$grid-gutter-width: 30px !default
|
||||
|
||||
// Components
|
||||
//
|
||||
// Define common padding and border radius sizes and more.
|
||||
|
||||
$line-height-lg: 1.5 !default
|
||||
$line-height-sm: 1.5 !default
|
||||
|
||||
$border-width: 1px !default
|
||||
$border-color: $gray-300 !default
|
||||
|
||||
$border-radius: 0.25rem !default
|
||||
$border-radius-lg: 0.3rem !default
|
||||
$border-radius-sm: 0.2rem !default
|
||||
|
||||
$box-shadow-sm: 0 0.125rem 0.25rem rgba($black, 0.075) !default
|
||||
$box-shadow: 0 0.5rem 1rem rgba($black, 0.15) !default
|
||||
$box-shadow-lg: 0 1rem 3rem rgba($black, 0.175) !default
|
||||
|
||||
$component-active-color: $white !default
|
||||
$component-active-bg: theme-color("primary") !default
|
||||
|
||||
$caret-width: 0.3em !default
|
||||
|
||||
$transition-base: all 0.2s ease-in-out !default
|
||||
$transition-fade: opacity 0.15s linear !default
|
||||
$transition-collapse: height 0.35s ease !default
|
||||
|
||||
// Fonts
|
||||
//
|
||||
// Font, line-height, and color for body text, headings, and more.
|
||||
|
||||
// stylelint-disable value-keyword-case
|
||||
$font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !default
|
||||
$font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace !default
|
||||
$font-family-base: $font-family-sans-serif !default
|
||||
|
||||
// stylelint-enable value-keyword-case
|
||||
|
||||
$font-size-base: 1rem !default
|
||||
|
||||
// Assumes the browser default, typically `16px`
|
||||
$font-size-lg: $font-size-base * 1.25 !default
|
||||
$font-size-sm: $font-size-base * 0.875 !default
|
||||
|
||||
$font-weight-light: 300 !default
|
||||
$font-weight-normal: 400 !default
|
||||
$font-weight-bold: 700 !default
|
||||
|
||||
$font-weight-base: $font-weight-normal !default
|
||||
$line-height-base: 1.5 !default
|
||||
|
||||
$h1-font-size: $font-size-base * 2.5 !default
|
||||
$h2-font-size: $font-size-base * 2 !default
|
||||
$h3-font-size: $font-size-base * 1.75 !default
|
||||
$h4-font-size: $font-size-base * 1.5 !default
|
||||
$h5-font-size: $font-size-base * 1.25 !default
|
||||
$h6-font-size: $font-size-base !default
|
||||
|
||||
$headings-margin-bottom: $spacer / 2 !default
|
||||
$headings-font-family: inherit !default
|
||||
$headings-font-weight: 500 !default
|
||||
$headings-line-height: 1.2 !default
|
||||
$headings-color: inherit !default
|
||||
|
||||
$display1-size: 6rem !default
|
||||
$display2-size: 5.5rem !default
|
||||
$display3-size: 4.5rem !default
|
||||
$display4-size: 3.5rem !default
|
||||
|
||||
$display1-weight: 300 !default
|
||||
$display2-weight: 300 !default
|
||||
$display3-weight: 300 !default
|
||||
$display4-weight: 300 !default
|
||||
$display-line-height: $headings-line-height !default
|
||||
|
||||
$lead-font-size: $font-size-base * 1.25 !default
|
||||
$lead-font-weight: 300 !default
|
||||
|
||||
$small-font-size: 80% !default
|
||||
|
||||
$text-muted: $gray-600 !default
|
||||
|
||||
$blockquote-small-color: $gray-600 !default
|
||||
$blockquote-font-size: $font-size-base * 1.25 !default
|
||||
|
||||
$hr-border-color: rgba($black, 0.1) !default
|
||||
$hr-border-width: $border-width !default
|
||||
|
||||
$mark-padding: 0.2em !default
|
||||
|
||||
$dt-font-weight: $font-weight-bold !default
|
||||
|
||||
$kbd-box-shadow: inset 0 -0.1rem 0 rgba($black, 0.25) !default
|
||||
$nested-kbd-font-weight: $font-weight-bold !default
|
||||
|
||||
$list-inline-padding: 0.5rem !default
|
||||
|
||||
$mark-bg: #fcf8e3 !default
|
||||
|
||||
$hr-margin-y: $spacer !default
|
||||
|
||||
// Tables
|
||||
//
|
||||
// Customizes the `.table` component with basic values, each used across all table variations.
|
||||
|
||||
$table-cell-padding: 0.75rem !default
|
||||
$table-cell-padding-sm: 0.3rem !default
|
||||
|
||||
$table-bg: transparent !default
|
||||
$table-accent-bg: rgba($black, 0.05) !default
|
||||
$table-hover-bg: rgba($black, 0.075) !default
|
||||
$table-active-bg: $table-hover-bg !default
|
||||
|
||||
$table-border-width: $border-width !default
|
||||
$table-border-color: $gray-300 !default
|
||||
|
||||
$table-head-bg: $gray-200 !default
|
||||
$table-head-color: $gray-700 !default
|
||||
|
||||
$table-dark-bg: $gray-900 !default
|
||||
$table-dark-accent-bg: rgba($white, 0.05) !default
|
||||
$table-dark-hover-bg: rgba($white, 0.075) !default
|
||||
$table-dark-border-color: lighten($gray-900, 7.5%) !default
|
||||
$table-dark-color: $body-bg !default
|
||||
|
||||
$table-striped-order: odd !default
|
||||
|
||||
$table-caption-color: $text-muted !default
|
||||
|
||||
// Buttons + Forms
|
||||
//
|
||||
// Shared variables that are reassigned to `$input-` and `$btn-` specific variables.
|
||||
|
||||
$input-btn-padding-y: 0.375rem !default
|
||||
$input-btn-padding-x: 0.75rem !default
|
||||
$input-btn-line-height: $line-height-base !default
|
||||
|
||||
$input-btn-focus-width: 0.2rem !default
|
||||
$input-btn-focus-color: rgba($component-active-bg, 0.25) !default
|
||||
$input-btn-focus-box-shadow: 0 0 0 $input-btn-focus-width $input-btn-focus-color !default
|
||||
|
||||
$input-btn-padding-y-sm: 0.25rem !default
|
||||
$input-btn-padding-x-sm: 0.5rem !default
|
||||
$input-btn-line-height-sm: $line-height-sm !default
|
||||
|
||||
$input-btn-padding-y-lg: 0.5rem !default
|
||||
$input-btn-padding-x-lg: 1rem !default
|
||||
$input-btn-line-height-lg: $line-height-lg !default
|
||||
|
||||
$input-btn-border-width: $border-width !default
|
||||
|
||||
// Buttons
|
||||
//
|
||||
// For each of Bootstrap's buttons, define text, background, and border color.
|
||||
|
||||
$btn-padding-y: $input-btn-padding-y !default
|
||||
$btn-padding-x: $input-btn-padding-x !default
|
||||
$btn-line-height: $input-btn-line-height !default
|
||||
|
||||
$btn-padding-y-sm: $input-btn-padding-y-sm !default
|
||||
$btn-padding-x-sm: $input-btn-padding-x-sm !default
|
||||
$btn-line-height-sm: $input-btn-line-height-sm !default
|
||||
|
||||
$btn-padding-y-lg: $input-btn-padding-y-lg !default
|
||||
$btn-padding-x-lg: $input-btn-padding-x-lg !default
|
||||
$btn-line-height-lg: $input-btn-line-height-lg !default
|
||||
|
||||
$btn-border-width: $input-btn-border-width !default
|
||||
|
||||
$btn-font-weight: $font-weight-normal !default
|
||||
$btn-box-shadow: inset 0 1px 0 rgba($white, 0.15), 0 1px 1px rgba($black, 0.075) !default
|
||||
$btn-focus-width: $input-btn-focus-width !default
|
||||
$btn-focus-box-shadow: $input-btn-focus-box-shadow !default
|
||||
$btn-disabled-opacity: 0.65 !default
|
||||
$btn-active-box-shadow: inset 0 3px 5px rgba($black, 0.125) !default
|
||||
|
||||
$btn-link-disabled-color: $gray-600 !default
|
||||
|
||||
$btn-block-spacing-y: 0.5rem !default
|
||||
|
||||
// Allows for customizing button radius independently from global border radius
|
||||
$btn-border-radius: $border-radius !default
|
||||
$btn-border-radius-lg: $border-radius-lg !default
|
||||
$btn-border-radius-sm: $border-radius-sm !default
|
||||
|
||||
$btn-transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out !default
|
||||
|
||||
// Forms
|
||||
|
||||
$label-margin-bottom: 0.5rem !default
|
||||
|
||||
$input-padding-y: $input-btn-padding-y !default
|
||||
$input-padding-x: $input-btn-padding-x !default
|
||||
$input-line-height: $input-btn-line-height !default
|
||||
|
||||
$input-padding-y-sm: $input-btn-padding-y-sm !default
|
||||
$input-padding-x-sm: $input-btn-padding-x-sm !default
|
||||
$input-line-height-sm: $input-btn-line-height-sm !default
|
||||
|
||||
$input-padding-y-lg: $input-btn-padding-y-lg !default
|
||||
$input-padding-x-lg: $input-btn-padding-x-lg !default
|
||||
$input-line-height-lg: $input-btn-line-height-lg !default
|
||||
|
||||
$input-bg: $white !default
|
||||
$input-disabled-bg: $gray-200 !default
|
||||
|
||||
$input-color: $gray-700 !default
|
||||
$input-border-color: $gray-400 !default
|
||||
$input-border-width: $input-btn-border-width !default
|
||||
$input-box-shadow: inset 0 1px 1px rgba($black, 0.075) !default
|
||||
|
||||
$input-border-radius: $border-radius !default
|
||||
$input-border-radius-lg: $border-radius-lg !default
|
||||
$input-border-radius-sm: $border-radius-sm !default
|
||||
|
||||
$input-focus-bg: $input-bg !default
|
||||
$input-focus-border-color: lighten($component-active-bg, 25%) !default
|
||||
$input-focus-color: $input-color !default
|
||||
$input-focus-width: $input-btn-focus-width !default
|
||||
$input-focus-box-shadow: $input-btn-focus-box-shadow !default
|
||||
|
||||
$input-placeholder-color: $gray-600 !default
|
||||
$input-plaintext-color: $body-color !default
|
||||
|
||||
$input-height-border: $input-border-width * 2 !default
|
||||
|
||||
$input-height-inner: $font-size-base * $input-btn-line-height + $input-btn-padding-y * 2 !default
|
||||
$input-height: calc(#{$input-height-inner} + #{$input-height-border}) !default
|
||||
|
||||
$input-height-inner-sm: $font-size-sm * $input-btn-line-height-sm + $input-btn-padding-y-sm * 2 !default
|
||||
$input-height-sm: calc(#{$input-height-inner-sm} + #{$input-height-border}) !default
|
||||
|
||||
$input-height-inner-lg: $font-size-lg * $input-btn-line-height-lg + $input-btn-padding-y-lg * 2 !default
|
||||
$input-height-lg: calc(#{$input-height-inner-lg} + #{$input-height-border}) !default
|
||||
|
||||
$input-transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out !default
|
||||
|
||||
$form-text-margin-top: 0.25rem !default
|
||||
|
||||
$form-check-input-gutter: 1.25rem !default
|
||||
$form-check-input-margin-y: 0.3rem !default
|
||||
$form-check-input-margin-x: 0.25rem !default
|
||||
|
||||
$form-check-inline-margin-x: 0.75rem !default
|
||||
$form-check-inline-input-margin-x: 0.3125rem !default
|
||||
|
||||
$form-group-margin-bottom: 1rem !default
|
||||
|
||||
$input-group-addon-color: $input-color !default
|
||||
$input-group-addon-bg: $gray-200 !default
|
||||
$input-group-addon-border-color: $input-border-color !default
|
||||
|
||||
$custom-forms-transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out !default
|
||||
|
||||
$custom-control-gutter: 1.5rem !default
|
||||
$custom-control-spacer-x: 1rem !default
|
||||
|
||||
$custom-control-indicator-size: 1rem !default
|
||||
$custom-control-indicator-bg: $gray-300 !default
|
||||
$custom-control-indicator-bg-size: 50% 50% !default
|
||||
$custom-control-indicator-box-shadow: inset 0 0.25rem 0.25rem rgba($black, 0.1) !default
|
||||
|
||||
$custom-control-indicator-disabled-bg: $gray-200 !default
|
||||
$custom-control-label-disabled-color: $gray-600 !default
|
||||
|
||||
$custom-control-indicator-checked-color: $component-active-color !default
|
||||
$custom-control-indicator-checked-bg: $component-active-bg !default
|
||||
$custom-control-indicator-checked-disabled-bg: rgba(theme-color("primary"), 0.5) !default
|
||||
$custom-control-indicator-checked-box-shadow: none !default
|
||||
|
||||
$custom-control-indicator-focus-box-shadow: 0 0 0 1px $body-bg, $input-btn-focus-box-shadow !default
|
||||
|
||||
$custom-control-indicator-active-color: $component-active-color !default
|
||||
$custom-control-indicator-active-bg: lighten($component-active-bg, 35%) !default
|
||||
$custom-control-indicator-active-box-shadow: none !default
|
||||
|
||||
$custom-checkbox-indicator-border-radius: $border-radius !default
|
||||
$custom-checkbox-indicator-icon-checked: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='#{$custom-control-indicator-checked-color}' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3E%3C/svg%3E"), "#", "%23") !default
|
||||
|
||||
$custom-checkbox-indicator-indeterminate-bg: $component-active-bg !default
|
||||
$custom-checkbox-indicator-indeterminate-color: $custom-control-indicator-checked-color !default
|
||||
$custom-checkbox-indicator-icon-indeterminate: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3E%3Cpath stroke='#{$custom-checkbox-indicator-indeterminate-color}' d='M0 2h4'/%3E%3C/svg%3E"), "#", "%23") !default
|
||||
$custom-checkbox-indicator-indeterminate-box-shadow: none !default
|
||||
|
||||
$custom-radio-indicator-border-radius: 50% !default
|
||||
$custom-radio-indicator-icon-checked: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3E%3Ccircle r='3' fill='#{$custom-control-indicator-checked-color}'/%3E%3C/svg%3E"), "#", "%23") !default
|
||||
|
||||
$custom-select-padding-y: 0.375rem !default
|
||||
$custom-select-padding-x: 0.75rem !default
|
||||
$custom-select-height: $input-height !default
|
||||
$custom-select-indicator-padding: 1rem !default
|
||||
|
||||
// Extra padding to account for the presence of the background-image based indicator
|
||||
$custom-select-line-height: $input-btn-line-height !default
|
||||
$custom-select-color: $input-color !default
|
||||
$custom-select-disabled-color: $gray-600 !default
|
||||
$custom-select-bg: $input-bg !default
|
||||
$custom-select-disabled-bg: $gray-200 !default
|
||||
$custom-select-bg-size: 8px 10px !default
|
||||
|
||||
// In pixels because image dimensions
|
||||
$custom-select-indicator-color: $gray-800 !default
|
||||
$custom-select-indicator: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='#{$custom-select-indicator-color}' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E"), "#", "%23") !default
|
||||
$custom-select-border-width: $input-btn-border-width !default
|
||||
$custom-select-border-color: $input-border-color !default
|
||||
$custom-select-border-radius: $border-radius !default
|
||||
$custom-select-box-shadow: inset 0 1px 2px rgba($black, 0.075) !default
|
||||
|
||||
$custom-select-focus-border-color: $input-focus-border-color !default
|
||||
$custom-select-focus-width: $input-btn-focus-width !default
|
||||
$custom-select-focus-box-shadow: 0 0 0 $custom-select-focus-width rgba($custom-select-focus-border-color, 0.5) !default
|
||||
|
||||
$custom-select-font-size-sm: 75% !default
|
||||
$custom-select-height-sm: $input-height-sm !default
|
||||
|
||||
$custom-select-font-size-lg: 125% !default
|
||||
$custom-select-height-lg: $input-height-lg !default
|
||||
|
||||
$custom-range-track-width: 100% !default
|
||||
$custom-range-track-height: 0.5rem !default
|
||||
$custom-range-track-cursor: pointer !default
|
||||
$custom-range-track-bg: $gray-300 !default
|
||||
$custom-range-track-border-radius: 1rem !default
|
||||
$custom-range-track-box-shadow: inset 0 0.25rem 0.25rem rgba($black, 0.1) !default
|
||||
|
||||
$custom-range-thumb-width: 1rem !default
|
||||
$custom-range-thumb-height: $custom-range-thumb-width !default
|
||||
$custom-range-thumb-bg: $component-active-bg !default
|
||||
$custom-range-thumb-border: 0 !default
|
||||
$custom-range-thumb-border-radius: 1rem !default
|
||||
$custom-range-thumb-box-shadow: 0 0.1rem 0.25rem rgba($black, 0.1) !default
|
||||
$custom-range-thumb-focus-box-shadow: 0 0 0 1px $body-bg, $input-btn-focus-box-shadow !default
|
||||
$custom-range-thumb-active-bg: lighten($component-active-bg, 35%) !default
|
||||
|
||||
$custom-file-height: $input-height !default
|
||||
$custom-file-height-inner: $input-height-inner !default
|
||||
$custom-file-focus-border-color: $input-focus-border-color !default
|
||||
$custom-file-focus-box-shadow: $input-btn-focus-box-shadow !default
|
||||
$custom-file-disabled-bg: $input-disabled-bg !default
|
||||
|
||||
$custom-file-padding-y: $input-btn-padding-y !default
|
||||
$custom-file-padding-x: $input-btn-padding-x !default
|
||||
$custom-file-line-height: $input-btn-line-height !default
|
||||
$custom-file-color: $input-color !default
|
||||
$custom-file-bg: $input-bg !default
|
||||
$custom-file-border-width: $input-btn-border-width !default
|
||||
$custom-file-border-color: $input-border-color !default
|
||||
$custom-file-border-radius: $input-border-radius !default
|
||||
$custom-file-box-shadow: $input-box-shadow !default
|
||||
$custom-file-button-color: $custom-file-color !default
|
||||
$custom-file-button-bg: $input-group-addon-bg !default
|
||||
$custom-file-text: (en: "Browse") !default
|
||||
|
||||
// Form validation
|
||||
$form-feedback-margin-top: $form-text-margin-top !default
|
||||
$form-feedback-font-size: $small-font-size !default
|
||||
$form-feedback-valid-color: theme-color("success") !default
|
||||
$form-feedback-invalid-color: theme-color("danger") !default
|
||||
|
||||
// Dropdowns
|
||||
//
|
||||
// Dropdown menu container and contents.
|
||||
|
||||
$dropdown-min-width: 10rem !default
|
||||
$dropdown-padding-y: 0.5rem !default
|
||||
$dropdown-spacer: 0.125rem !default
|
||||
$dropdown-bg: $white !default
|
||||
$dropdown-border-color: rgba($black, 0.15) !default
|
||||
$dropdown-border-radius: $border-radius !default
|
||||
$dropdown-border-width: $border-width !default
|
||||
$dropdown-divider-bg: $gray-200 !default
|
||||
$dropdown-box-shadow: 0 0.5rem 1rem rgba($black, 0.175) !default
|
||||
|
||||
$dropdown-link-color: $gray-900 !default
|
||||
$dropdown-link-hover-color: darken($gray-900, 5%) !default
|
||||
$dropdown-link-hover-bg: $gray-100 !default
|
||||
|
||||
$dropdown-link-active-color: $component-active-color !default
|
||||
$dropdown-link-active-bg: $component-active-bg !default
|
||||
|
||||
$dropdown-link-disabled-color: $gray-600 !default
|
||||
|
||||
$dropdown-item-padding-y: 0.25rem !default
|
||||
$dropdown-item-padding-x: 1.5rem !default
|
||||
|
||||
$dropdown-header-color: $gray-600 !default
|
||||
|
||||
// Z-index master list
|
||||
//
|
||||
// Warning: Avoid customizing these values. They're used for a bird's eye view
|
||||
// of components dependent on the z-axis and are designed to all work together.
|
||||
|
||||
$zindex-dropdown: 1000 !default
|
||||
$zindex-sticky: 1020 !default
|
||||
$zindex-fixed: 1030 !default
|
||||
$zindex-modal-backdrop: 1040 !default
|
||||
$zindex-modal: 1050 !default
|
||||
$zindex-popover: 1060 !default
|
||||
$zindex-tooltip: 1070 !default
|
||||
|
||||
// Navs
|
||||
|
||||
$nav-link-padding-y: 0.5rem !default
|
||||
$nav-link-padding-x: 1rem !default
|
||||
$nav-link-disabled-color: $gray-600 !default
|
||||
|
||||
$nav-tabs-border-color: $gray-300 !default
|
||||
$nav-tabs-border-width: $border-width !default
|
||||
$nav-tabs-border-radius: $border-radius !default
|
||||
$nav-tabs-link-hover-border-color: $gray-200 $gray-200 $nav-tabs-border-color !default
|
||||
$nav-tabs-link-active-color: $gray-700 !default
|
||||
$nav-tabs-link-active-bg: $body-bg !default
|
||||
$nav-tabs-link-active-border-color: $gray-300 $gray-300 $nav-tabs-link-active-bg !default
|
||||
|
||||
$nav-pills-border-radius: $border-radius !default
|
||||
$nav-pills-link-active-color: $component-active-color !default
|
||||
$nav-pills-link-active-bg: $component-active-bg !default
|
||||
|
||||
$nav-divider-color: $gray-200 !default
|
||||
$nav-divider-margin-y: $spacer / 2 !default
|
||||
|
||||
// Navbar
|
||||
|
||||
$navbar-padding-y: $spacer / 2 !default
|
||||
$navbar-padding-x: $spacer !default
|
||||
|
||||
$navbar-nav-link-padding-x: 0.5rem !default
|
||||
|
||||
$navbar-brand-font-size: $font-size-lg !default
|
||||
|
||||
// Compute the navbar-brand padding-y so the navbar-brand will have the same height as navbar-text and nav-link
|
||||
$nav-link-height: $font-size-base * $line-height-base + $nav-link-padding-y * 2 !default
|
||||
$navbar-brand-height: $navbar-brand-font-size * $line-height-base !default
|
||||
$navbar-brand-padding-y: ($nav-link-height - $navbar-brand-height) / 2 !default
|
||||
|
||||
$navbar-toggler-padding-y: 0.25rem !default
|
||||
$navbar-toggler-padding-x: 0.75rem !default
|
||||
$navbar-toggler-font-size: $font-size-lg !default
|
||||
$navbar-toggler-border-radius: $btn-border-radius !default
|
||||
|
||||
$navbar-dark-color: rgba($white, 0.5) !default
|
||||
$navbar-dark-hover-color: rgba($white, 0.75) !default
|
||||
$navbar-dark-active-color: $white !default
|
||||
$navbar-dark-disabled-color: rgba($white, 0.25) !default
|
||||
$navbar-dark-toggler-icon-bg: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='#{$navbar-dark-color}' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E"), "#", "%23") !default
|
||||
$navbar-dark-toggler-border-color: rgba($white, 0.1) !default
|
||||
|
||||
$navbar-light-color: rgba($black, 0.5) !default
|
||||
$navbar-light-hover-color: rgba($black, 0.7) !default
|
||||
$navbar-light-active-color: rgba($black, 0.9) !default
|
||||
$navbar-light-disabled-color: rgba($black, 0.3) !default
|
||||
$navbar-light-toggler-icon-bg: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='#{$navbar-light-color}' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E"), "#", "%23") !default
|
||||
$navbar-light-toggler-border-color: rgba($black, 0.1) !default
|
||||
|
||||
// Pagination
|
||||
|
||||
$pagination-padding-y: 0.5rem !default
|
||||
$pagination-padding-x: 0.75rem !default
|
||||
$pagination-padding-y-sm: 0.25rem !default
|
||||
$pagination-padding-x-sm: 0.5rem !default
|
||||
$pagination-padding-y-lg: 0.75rem !default
|
||||
$pagination-padding-x-lg: 1.5rem !default
|
||||
$pagination-line-height: 1.25 !default
|
||||
|
||||
$pagination-color: $link-color !default
|
||||
$pagination-bg: $white !default
|
||||
$pagination-border-width: $border-width !default
|
||||
$pagination-border-color: $gray-300 !default
|
||||
|
||||
$pagination-focus-box-shadow: $input-btn-focus-box-shadow !default
|
||||
$pagination-focus-outline: 0 !default
|
||||
|
||||
$pagination-hover-color: $link-hover-color !default
|
||||
$pagination-hover-bg: $gray-200 !default
|
||||
$pagination-hover-border-color: $gray-300 !default
|
||||
|
||||
$pagination-active-color: $component-active-color !default
|
||||
$pagination-active-bg: $component-active-bg !default
|
||||
$pagination-active-border-color: $pagination-active-bg !default
|
||||
|
||||
$pagination-disabled-color: $gray-600 !default
|
||||
$pagination-disabled-bg: $white !default
|
||||
$pagination-disabled-border-color: $gray-300 !default
|
||||
|
||||
// Jumbotron
|
||||
|
||||
$jumbotron-padding: 2rem !default
|
||||
$jumbotron-bg: $gray-200 !default
|
||||
|
||||
// Cards
|
||||
|
||||
$card-spacer-y: 0.75rem !default
|
||||
$card-spacer-x: 1.25rem !default
|
||||
$card-border-width: $border-width !default
|
||||
$card-border-radius: $border-radius !default
|
||||
$card-border-color: rgba($black, 0.125) !default
|
||||
$card-inner-border-radius: calc(#{$card-border-radius} - #{$card-border-width}) !default
|
||||
$card-cap-bg: rgba($black, 0.03) !default
|
||||
$card-bg: $white !default
|
||||
|
||||
$card-img-overlay-padding: 1.25rem !default
|
||||
|
||||
$card-group-margin: $grid-gutter-width / 2 !default
|
||||
$card-deck-margin: $card-group-margin !default
|
||||
|
||||
$card-columns-count: 3 !default
|
||||
$card-columns-gap: 1.25rem !default
|
||||
$card-columns-margin: $card-spacer-y !default
|
||||
|
||||
// Tooltips
|
||||
|
||||
$tooltip-font-size: $font-size-sm !default
|
||||
$tooltip-max-width: 200px !default
|
||||
$tooltip-color: $white !default
|
||||
$tooltip-bg: $black !default
|
||||
$tooltip-border-radius: $border-radius !default
|
||||
$tooltip-opacity: 0.9 !default
|
||||
$tooltip-padding-y: 0.25rem !default
|
||||
$tooltip-padding-x: 0.5rem !default
|
||||
$tooltip-margin: 0 !default
|
||||
|
||||
$tooltip-arrow-width: 0.8rem !default
|
||||
$tooltip-arrow-height: 0.4rem !default
|
||||
$tooltip-arrow-color: $tooltip-bg !default
|
||||
|
||||
// Popovers
|
||||
|
||||
$popover-font-size: $font-size-sm !default
|
||||
$popover-bg: $white !default
|
||||
$popover-max-width: 276px !default
|
||||
$popover-border-width: $border-width !default
|
||||
$popover-border-color: rgba($black, 0.2) !default
|
||||
$popover-border-radius: $border-radius-lg !default
|
||||
$popover-box-shadow: 0 0.25rem 0.5rem rgba($black, 0.2) !default
|
||||
|
||||
$popover-header-bg: darken($popover-bg, 3%) !default
|
||||
$popover-header-color: $headings-color !default
|
||||
$popover-header-padding-y: 0.5rem !default
|
||||
$popover-header-padding-x: 0.75rem !default
|
||||
|
||||
$popover-body-color: $body-color !default
|
||||
$popover-body-padding-y: $popover-header-padding-y !default
|
||||
$popover-body-padding-x: $popover-header-padding-x !default
|
||||
|
||||
$popover-arrow-width: 1rem !default
|
||||
$popover-arrow-height: 0.5rem !default
|
||||
$popover-arrow-color: $popover-bg !default
|
||||
|
||||
$popover-arrow-outer-color: fade-in($popover-border-color, 0.05) !default
|
||||
|
||||
// Badges
|
||||
|
||||
$badge-font-size: 75% !default
|
||||
$badge-font-weight: $font-weight-bold !default
|
||||
$badge-padding-y: 0.25em !default
|
||||
$badge-padding-x: 0.4em !default
|
||||
$badge-border-radius: $border-radius !default
|
||||
|
||||
$badge-pill-padding-x: 0.6em !default
|
||||
|
||||
// Use a higher than normal value to ensure completely rounded edges when
|
||||
// customizing padding or font-size on labels.
|
||||
$badge-pill-border-radius: 10rem !default
|
||||
|
||||
// Modals
|
||||
|
||||
// Padding applied to the modal body
|
||||
$modal-inner-padding: 1rem !default
|
||||
|
||||
$modal-dialog-margin: 0.5rem !default
|
||||
$modal-dialog-margin-y-sm-up: 1.75rem !default
|
||||
|
||||
$modal-title-line-height: $line-height-base !default
|
||||
|
||||
$modal-content-bg: $white !default
|
||||
$modal-content-border-color: rgba($black, 0.2) !default
|
||||
$modal-content-border-width: $border-width !default
|
||||
$modal-content-border-radius: $border-radius-lg !default
|
||||
$modal-content-box-shadow-xs: 0 0.25rem 0.5rem rgba($black, 0.5) !default
|
||||
$modal-content-box-shadow-sm-up: 0 0.5rem 1rem rgba($black, 0.5) !default
|
||||
|
||||
$modal-backdrop-bg: $black !default
|
||||
$modal-backdrop-opacity: 0.5 !default
|
||||
$modal-header-border-color: $gray-200 !default
|
||||
$modal-footer-border-color: $modal-header-border-color !default
|
||||
$modal-header-border-width: $modal-content-border-width !default
|
||||
$modal-footer-border-width: $modal-header-border-width !default
|
||||
$modal-header-padding: 1rem !default
|
||||
|
||||
$modal-lg: 800px !default
|
||||
$modal-md: 500px !default
|
||||
$modal-sm: 300px !default
|
||||
|
||||
$modal-transition: transform 0.3s ease-out !default
|
||||
|
||||
// Alerts
|
||||
//
|
||||
// Define alert colors, border radius, and padding.
|
||||
|
||||
$alert-padding-y: 0.75rem !default
|
||||
$alert-padding-x: 1.25rem !default
|
||||
$alert-margin-bottom: 1rem !default
|
||||
$alert-border-radius: $border-radius !default
|
||||
$alert-link-font-weight: $font-weight-bold !default
|
||||
$alert-border-width: $border-width !default
|
||||
|
||||
$alert-bg-level: -10 !default
|
||||
$alert-border-level: -9 !default
|
||||
$alert-color-level: 6 !default
|
||||
|
||||
// Progress bars
|
||||
|
||||
$progress-height: 1rem !default
|
||||
$progress-font-size: $font-size-base * 0.75 !default
|
||||
$progress-bg: $gray-200 !default
|
||||
$progress-border-radius: $border-radius !default
|
||||
$progress-box-shadow: inset 0 0.1rem 0.1rem rgba($black, 0.1) !default
|
||||
$progress-bar-color: $white !default
|
||||
$progress-bar-bg: theme-color("primary") !default
|
||||
$progress-bar-animation-timing: 1s linear infinite !default
|
||||
$progress-bar-transition: width 0.6s ease !default
|
||||
|
||||
// List group
|
||||
|
||||
$list-group-bg: $white !default
|
||||
$list-group-border-color: rgba($black, 0.125) !default
|
||||
$list-group-border-width: $border-width !default
|
||||
$list-group-border-radius: $border-radius !default
|
||||
|
||||
$list-group-item-padding-y: 0.75rem !default
|
||||
$list-group-item-padding-x: 1.25rem !default
|
||||
|
||||
$list-group-hover-bg: $gray-100 !default
|
||||
$list-group-active-color: $component-active-color !default
|
||||
$list-group-active-bg: $component-active-bg !default
|
||||
$list-group-active-border-color: $list-group-active-bg !default
|
||||
|
||||
$list-group-disabled-color: $gray-600 !default
|
||||
$list-group-disabled-bg: $list-group-bg !default
|
||||
|
||||
$list-group-action-color: $gray-700 !default
|
||||
$list-group-action-hover-color: $list-group-action-color !default
|
||||
|
||||
$list-group-action-active-color: $body-color !default
|
||||
$list-group-action-active-bg: $gray-200 !default
|
||||
|
||||
// Image thumbnails
|
||||
|
||||
$thumbnail-padding: 0.25rem !default
|
||||
$thumbnail-bg: $body-bg !default
|
||||
$thumbnail-border-width: $border-width !default
|
||||
$thumbnail-border-color: $gray-300 !default
|
||||
$thumbnail-border-radius: $border-radius !default
|
||||
$thumbnail-box-shadow: 0 1px 2px rgba($black, 0.075) !default
|
||||
|
||||
// Figures
|
||||
|
||||
$figure-caption-font-size: 90% !default
|
||||
$figure-caption-color: $gray-600 !default
|
||||
|
||||
// Breadcrumbs
|
||||
|
||||
$breadcrumb-padding-y: 0.75rem !default
|
||||
$breadcrumb-padding-x: 1rem !default
|
||||
$breadcrumb-item-padding: 0.5rem !default
|
||||
|
||||
$breadcrumb-margin-bottom: 1rem !default
|
||||
|
||||
$breadcrumb-bg: $gray-200 !default
|
||||
$breadcrumb-divider-color: $gray-600 !default
|
||||
$breadcrumb-active-color: $gray-600 !default
|
||||
$breadcrumb-divider: quote("/") !default
|
||||
|
||||
$breadcrumb-border-radius: $border-radius !default
|
||||
|
||||
// Carousel
|
||||
|
||||
$carousel-control-color: $white !default
|
||||
$carousel-control-width: 15% !default
|
||||
$carousel-control-opacity: 0.5 !default
|
||||
|
||||
$carousel-indicator-width: 30px !default
|
||||
$carousel-indicator-height: 3px !default
|
||||
$carousel-indicator-spacer: 3px !default
|
||||
$carousel-indicator-active-bg: $white !default
|
||||
|
||||
$carousel-caption-width: 70% !default
|
||||
$carousel-caption-color: $white !default
|
||||
|
||||
$carousel-control-icon-width: 20px !default
|
||||
|
||||
$carousel-control-prev-icon-bg: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='#{$carousel-control-color}' viewBox='0 0 8 8'%3E%3Cpath d='M5.25 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3E%3C/svg%3E"), "#", "%23") !default
|
||||
$carousel-control-next-icon-bg: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='#{$carousel-control-color}' viewBox='0 0 8 8'%3E%3Cpath d='M2.75 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3E%3C/svg%3E"), "#", "%23") !default
|
||||
|
||||
$carousel-transition: transform 0.6s ease !default
|
||||
|
||||
// Define transform transition first if using multiple transitions (e.g., `transform 2s ease, opacity .5s ease-out`)
|
||||
|
||||
// Close
|
||||
|
||||
$close-font-size: $font-size-base * 1.5 !default
|
||||
$close-font-weight: $font-weight-bold !default
|
||||
$close-color: $black !default
|
||||
$close-text-shadow: 0 1px 0 $white !default
|
||||
|
||||
// Code
|
||||
|
||||
$code-font-size: 87.5% !default
|
||||
$code-color: $pink !default
|
||||
|
||||
$kbd-padding-y: 0.2rem !default
|
||||
$kbd-padding-x: 0.4rem !default
|
||||
$kbd-font-size: $code-font-size !default
|
||||
$kbd-color: $white !default
|
||||
$kbd-bg: $gray-900 !default
|
||||
|
||||
$pre-color: $gray-900 !default
|
||||
$pre-scrollable-max-height: 340px !default
|
||||
|
||||
// Printing
|
||||
$print-page-size: a3 !default
|
||||
$print-body-min-width: map-get($grid-breakpoints, "lg") !default
|
31
static/assets/bootstrap/sass/bootstrap-grid.sass
Normal file
31
static/assets/bootstrap/sass/bootstrap-grid.sass
Normal file
@@ -0,0 +1,31 @@
|
||||
/*!
|
||||
* Bootstrap Grid v4.1.2 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2018 The Bootstrap Authors
|
||||
* Copyright 2011-2018 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
|
||||
@at-root
|
||||
@-ms-viewport
|
||||
width: device-width
|
||||
|
||||
// stylelint-disable-line at-rule-no-vendor-prefix
|
||||
|
||||
html
|
||||
box-sizing: border-box
|
||||
-ms-overflow-style: scrollbar
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after
|
||||
box-sizing: inherit
|
||||
|
||||
@import functions
|
||||
@import variables
|
||||
|
||||
@import mixins/breakpoints
|
||||
@import mixins/grid-framework
|
||||
@import mixins/grid
|
||||
|
||||
@import grid
|
||||
@import utilities/display
|
||||
@import utilities/flex
|
11
static/assets/bootstrap/sass/bootstrap-reboot.sass
Normal file
11
static/assets/bootstrap/sass/bootstrap-reboot.sass
Normal file
@@ -0,0 +1,11 @@
|
||||
/*!
|
||||
* Bootstrap Reboot v4.1.2 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2018 The Bootstrap Authors
|
||||
* Copyright 2011-2018 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
||||
|
||||
@import functions
|
||||
@import variables
|
||||
@import mixins
|
||||
@import reboot
|
41
static/assets/bootstrap/sass/bootstrap.sass
Normal file
41
static/assets/bootstrap/sass/bootstrap.sass
Normal file
@@ -0,0 +1,41 @@
|
||||
/*!
|
||||
* Bootstrap v4.1.2 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2018 The Bootstrap Authors
|
||||
* Copyright 2011-2018 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
|
||||
@import functions
|
||||
@import variables
|
||||
@import mixins
|
||||
@import root
|
||||
@import reboot
|
||||
@import type
|
||||
@import images
|
||||
@import code
|
||||
@import grid
|
||||
@import tables
|
||||
@import forms
|
||||
@import buttons
|
||||
@import transitions
|
||||
@import dropdown
|
||||
@import button-group
|
||||
@import input-group
|
||||
@import custom-forms
|
||||
@import nav
|
||||
@import navbar
|
||||
@import card
|
||||
@import breadcrumb
|
||||
@import pagination
|
||||
@import badge
|
||||
@import jumbotron
|
||||
@import alert
|
||||
@import progress
|
||||
@import media
|
||||
@import list-group
|
||||
@import close
|
||||
@import modal
|
||||
@import tooltip
|
||||
@import popover
|
||||
@import carousel
|
||||
@import utilities
|
||||
@import print
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user