diff --git a/.gitignore b/.gitignore index e8cd280ccd62..ecb4236cd499 100644 --- a/.gitignore +++ b/.gitignore @@ -76,13 +76,15 @@ lms/static/certificates/css/ cms/static/css/ ### Styling generated from templates -lms/static/sass/lms-main.scss -lms/static/sass/lms-main-rtl.scss -lms/static/sass/lms-course.scss -lms/static/sass/lms-course-rtl.scss -lms/static/sass/lms-footer.scss -lms/static/sass/lms-footer-rtl.scss - +lms/static/sass/*.css +lms/static/sass/*.css.map +lms/static/certificates/sass/*.css +lms/static/themed_sass/ +cms/static/css/ +cms/static/sass/*.css +cms/static/sass/*.css.map +cms/static/themed_sass/ +themes/**/css/*.css ### Logging artifacts log/ diff --git a/cms/envs/common.py b/cms/envs/common.py index 4cb42bbcfee9..973f0551e46c 100644 --- a/cms/envs/common.py +++ b/cms/envs/common.py @@ -36,7 +36,7 @@ # Although this module itself may not use these imported variables, other dependent modules may. from lms.envs.common import ( USE_TZ, TECH_SUPPORT_EMAIL, PLATFORM_NAME, BUGS_EMAIL, DOC_STORE_CONFIG, DATA_DIR, ALL_LANGUAGES, WIKI_ENABLED, - update_module_store_settings, ASSET_IGNORE_REGEX, COPYRIGHT_YEAR, PARENTAL_CONSENT_AGE_LIMIT, + update_module_store_settings, ASSET_IGNORE_REGEX, COPYRIGHT_YEAR, PARENTAL_CONSENT_AGE_LIMIT, COMP_THEME_DIR, # The following PROFILE_IMAGE_* settings are included as they are # indirectly accessed through the email opt-in API, which is # technically accessible through the CMS via legacy URLs. @@ -754,6 +754,9 @@ 'static_replace', 'require', + # Theming + 'openedx.core.djangoapps.theming', + # comment common 'django_comment_common', diff --git a/cms/static/sass/_variables.scss b/cms/static/sass/_variables.scss index acdc7e31b31b..ad20b5722128 100644 --- a/cms/static/sass/_variables.scss +++ b/cms/static/sass/_variables.scss @@ -2,6 +2,7 @@ // ==================== // Table of Contents +// * +Paths // * +Grid // * +Fonts // * +Colors - Utility @@ -15,6 +16,10 @@ $baseline: 20px; +// +Paths +// ==================== +$static-path: '..' !default; + // +Grid // ==================== $gw-column: ($baseline*3); diff --git a/cms/static/sass/assets/_fonts.scss b/cms/static/sass/assets/_fonts.scss index 65c1c91f3e05..42349696797c 100644 --- a/cms/static/sass/assets/_fonts.scss +++ b/cms/static/sass/assets/_fonts.scss @@ -3,9 +3,9 @@ @font-face { font-family: 'Open Sans'; src: - url('../fonts/OpenSans/OpenSans-Light-webfont.woff2') format('woff2'), - url('../fonts/OpenSans/OpenSans-Light-webfont.woff') format('woff'), - url('../fonts/OpenSans/OpenSans-Light-webfont.ttf') format('truetype'); + url('#{$static-path}/fonts/OpenSans/OpenSans-Light-webfont.woff2') format('woff2'), + url('#{$static-path}/fonts/OpenSans/OpenSans-Light-webfont.woff') format('woff'), + url('#{$static-path}/fonts/OpenSans/OpenSans-Light-webfont.ttf') format('truetype'); font-weight: 300; font-style: normal; } @@ -13,9 +13,9 @@ @font-face { font-family: 'Open Sans'; src: - url('../fonts/OpenSans/OpenSans-LightItalic-webfont.woff2') format('woff2'), - url('../fonts/OpenSans/OpenSans-LightItalic-webfont.woff') format('woff'), - url('../fonts/OpenSans/OpenSans-LightItalic-webfont.ttf') format('truetype'); + url('#{$static-path}/fonts/OpenSans/OpenSans-LightItalic-webfont.woff2') format('woff2'), + url('#{$static-path}/fonts/OpenSans/OpenSans-LightItalic-webfont.woff') format('woff'), + url('#{$static-path}/fonts/OpenSans/OpenSans-LightItalic-webfont.ttf') format('truetype'); font-weight: 300; font-style: italic; } @@ -23,9 +23,9 @@ @font-face { font-family: 'Open Sans'; src: - url('../fonts/OpenSans/OpenSans-Regular-webfont.woff2') format('woff2'), - url('../fonts/OpenSans/OpenSans-Regular-webfont.woff') format('woff'), - url('../fonts/OpenSans/OpenSans-Regular-webfont.ttf') format('truetype'); + url('#{$static-path}/fonts/OpenSans/OpenSans-Regular-webfont.woff2') format('woff2'), + url('#{$static-path}/fonts/OpenSans/OpenSans-Regular-webfont.woff') format('woff'), + url('#{$static-path}/fonts/OpenSans/OpenSans-Regular-webfont.ttf') format('truetype'); font-weight: 400; font-style: normal; } @@ -33,9 +33,9 @@ @font-face { font-family: 'Open Sans'; src: - url('../fonts/OpenSans/OpenSans-Italic-webfont.woff2') format('woff2'), - url('../fonts/OpenSans/OpenSans-Italic-webfont.woff') format('woff'), - url('../fonts/OpenSans/OpenSans-Italic-webfont.ttf') format('truetype'); + url('#{$static-path}/fonts/OpenSans/OpenSans-Italic-webfont.woff2') format('woff2'), + url('#{$static-path}/fonts/OpenSans/OpenSans-Italic-webfont.woff') format('woff'), + url('#{$static-path}/fonts/OpenSans/OpenSans-Italic-webfont.ttf') format('truetype'); font-weight: 400; font-style: italic; } @@ -43,9 +43,9 @@ @font-face { font-family: 'Open Sans'; src: - url('../fonts/OpenSans/OpenSans-Semibold-webfont.woff2') format('woff2'), - url('../fonts/OpenSans/OpenSans-Semibold-webfont.woff') format('woff'), - url('../fonts/OpenSans/OpenSans-Semibold-webfont.ttf') format('truetype'); + url('#{$static-path}/fonts/OpenSans/OpenSans-Semibold-webfont.woff2') format('woff2'), + url('#{$static-path}/fonts/OpenSans/OpenSans-Semibold-webfont.woff') format('woff'), + url('#{$static-path}/fonts/OpenSans/OpenSans-Semibold-webfont.ttf') format('truetype'); font-weight: 600; font-style: normal; } @@ -53,9 +53,9 @@ @font-face { font-family: 'Open Sans'; src: - url('../fonts/OpenSans/OpenSans-SemiboldItalic-webfont.woff2') format('woff2'), - url('../fonts/OpenSans/OpenSans-SemiboldItalic-webfont.woff') format('woff'), - url('../fonts/OpenSans/OpenSans-SemiboldItalic-webfont.ttf') format('truetype'); + url('#{$static-path}/fonts/OpenSans/OpenSans-SemiboldItalic-webfont.woff2') format('woff2'), + url('#{$static-path}/fonts/OpenSans/OpenSans-SemiboldItalic-webfont.woff') format('woff'), + url('#{$static-path}/fonts/OpenSans/OpenSans-SemiboldItalic-webfont.ttf') format('truetype'); font-weight: 600; font-style: italic; } @@ -63,9 +63,9 @@ @font-face { font-family: 'Open Sans'; src: - url('../fonts/OpenSans/OpenSans-Bold-webfont.woff2') format('woff2'), - url('../fonts/OpenSans/OpenSans-Bold-webfont.woff') format('woff'), - url('../fonts/OpenSans/OpenSans-Bold-webfont.ttf') format('truetype'); + url('#{$static-path}/fonts/OpenSans/OpenSans-Bold-webfont.woff2') format('woff2'), + url('#{$static-path}/fonts/OpenSans/OpenSans-Bold-webfont.woff') format('woff'), + url('#{$static-path}/fonts/OpenSans/OpenSans-Bold-webfont.ttf') format('truetype'); font-weight: 700; font-style: normal; } @@ -73,9 +73,9 @@ @font-face { font-family: 'Open Sans'; src: - url('../fonts/OpenSans/OpenSans-BoldItalic-webfont.woff2') format('woff2'), - url('../fonts/OpenSans/OpenSans-BoldItalic-webfont.woff') format('woff'), - url('../fonts/OpenSans/OpenSans-BoldItalic-webfont.ttf') format('truetype'); + url('#{$static-path}/fonts/OpenSans/OpenSans-BoldItalic-webfont.woff2') format('woff2'), + url('#{$static-path}/fonts/OpenSans/OpenSans-BoldItalic-webfont.woff') format('woff'), + url('#{$static-path}/fonts/OpenSans/OpenSans-BoldItalic-webfont.ttf') format('truetype'); font-weight: 700; font-style: italic; } diff --git a/cms/static/sass/assets/_graphics.scss b/cms/static/sass/assets/_graphics.scss index 9b0253b08590..e8a3f8c8a52f 100644 --- a/cms/static/sass/assets/_graphics.scss +++ b/cms/static/sass/assets/_graphics.scss @@ -7,7 +7,7 @@ width: 7px; height: 22px; margin-left: ($baseline/2); - background: url(../images/drag-handles.png) no-repeat; + background: url('#{$static-path}/images/drag-handles.png') no-repeat; cursor: move; } @@ -15,33 +15,33 @@ display: inline-block; width: ($baseline*3); height: ($baseline*3); - background: url(../images/large-advanced-icon.png) center no-repeat; + background: url('#{$static-path}/images/large-advanced-icon.png') center no-repeat; } .large-discussion-icon { display: inline-block; width: ($baseline*3); height: ($baseline*3); - background: url(../images/large-discussion-icon.png) center no-repeat; + background: url('#{$static-path}/images/large-discussion-icon.png') center no-repeat; } .large-html-icon { display: inline-block; width: ($baseline*3); height: ($baseline*3); - background: url(../images/large-html-icon.png) center no-repeat; + background: url('#{$static-path}/images/large-html-icon.png') center no-repeat; } .large-problem-icon { display: inline-block; width: ($baseline*3); height: ($baseline*3); - background: url(../images/large-problem-icon.png) center no-repeat; + background: url('#{$static-path}/images/large-problem-icon.png') center no-repeat; } .large-video-icon { display: inline-block; width: ($baseline*3); height: ($baseline*3); - background: url(../images/large-video-icon.png) center no-repeat; + background: url('#{$static-path}/images/large-video-icon.png') center no-repeat; } diff --git a/cms/static/sass/elements/_controls.scss b/cms/static/sass/elements/_controls.scss index 45df38f5ec41..57ce75625e19 100644 --- a/cms/static/sass/elements/_controls.scss +++ b/cms/static/sass/elements/_controls.scss @@ -295,12 +295,12 @@ // CASE: right to left layout @include rtl { - background: transparent url("../images/drag-handles.png") no-repeat left center; + background: transparent url("#{$static-path}/images/drag-handles.png") no-repeat left center; } // CASE: left to right layout @include ltr { - background: transparent url("../images/drag-handles.png") no-repeat right center; + background: transparent url("#{$static-path}/images/drag-handles.png") no-repeat right center; } } diff --git a/cms/static/sass/elements/_creative-commons.scss b/cms/static/sass/elements/_creative-commons.scss index d14351f83ba8..dc3a5a0b05ea 100644 --- a/cms/static/sass/elements/_creative-commons.scss +++ b/cms/static/sass/elements/_creative-commons.scss @@ -1,10 +1,10 @@ @font-face { font-family: 'CreativeCommons'; - src: url('../fonts/CreativeCommons/cc.eot'); - src: url('../fonts/CreativeCommons/cc.eot#iefix') format('embedded-opentype'), - url('../fonts/CreativeCommons/cc.woff') format('woff'), - url('../fonts/CreativeCommons/cc.ttf') format('truetype'), - url('../fonts/CreativeCommons/cc.svg#CreativeCommons') format('svg'); + src: url('#{$static-path}/fonts/CreativeCommons/cc.eot'); + src: url('#{$static-path}/fonts/CreativeCommons/cc.eot#iefix') format('embedded-opentype'), + url('#{$static-path}/fonts/CreativeCommons/cc.woff') format('woff'), + url('#{$static-path}/fonts/CreativeCommons/cc.ttf') format('truetype'), + url('#{$static-path}/fonts/CreativeCommons/cc.svg#CreativeCommons') format('svg'); font-weight: normal; font-style: normal; } diff --git a/cms/static/sass/elements/_forms.scss b/cms/static/sass/elements/_forms.scss index 307bd31d98ae..7bec93b1adb9 100644 --- a/cms/static/sass/elements/_forms.scss +++ b/cms/static/sass/elements/_forms.scss @@ -456,7 +456,7 @@ input.search { @include box-sizing(border-box); border: 1px solid $darkGrey; border-radius: 20px; - background: url(../images/search-icon.png) no-repeat 8px 7px #edf1f5; + background: url('#{$static-path}/images/search-icon.png') no-repeat 8px 7px #edf1f5; font-family: 'Open Sans', sans-serif; color: $baseFontColor; outline: 0; diff --git a/cms/static/sass/elements/_uploaded-assets.scss b/cms/static/sass/elements/_uploaded-assets.scss index 2253d2e6601e..e8f98443bd47 100644 --- a/cms/static/sass/elements/_uploaded-assets.scss +++ b/cms/static/sass/elements/_uploaded-assets.scss @@ -100,7 +100,7 @@ } &.is-locked { - background-image: url('../images/bg-micro-stripes.png'); + background-image: url('#{$static-path}/images/bg-micro-stripes.png'); background-position: 0 0; background-repeat: repeat; } diff --git a/cms/static/sass/views/_assets.scss b/cms/static/sass/views/_assets.scss index 24284d9dfd3d..f0df189d42e9 100644 --- a/cms/static/sass/views/_assets.scss +++ b/cms/static/sass/views/_assets.scss @@ -299,7 +299,7 @@ } &.is-locked { - background-image: url('../images/bg-micro-stripes.png'); + background-image: url('#{$static-path}/images/bg-micro-stripes.png'); background-position: 0 0; background-repeat: repeat; } diff --git a/cms/static/sass/views/_static-pages.scss b/cms/static/sass/views/_static-pages.scss index a9cf9c39d9fc..302b56155127 100644 --- a/cms/static/sass/views/_static-pages.scss +++ b/cms/static/sass/views/_static-pages.scss @@ -197,7 +197,7 @@ } .drag-handle { - background: url(../images/drag-handles.png) center no-repeat #fff; + background: url('#{$static-path}/images/drag-handles.png') center no-repeat #fff; } } @@ -210,10 +210,10 @@ width: 35px; height: 100%; border: none; - background: url(../images/drag-handles.png) center no-repeat #fff; + background: url('#{$static-path}/images/drag-handles.png') center no-repeat #fff; &:hover { - background: url(../images/drag-handles.png) center no-repeat #fff; + background: url('#{$static-path}/images/drag-handles.png') center no-repeat #fff; } &.is-fixed { diff --git a/cms/templates/widgets/header.html b/cms/templates/widgets/header.html index e4e2a9cf22b0..836a618c8f3d 100644 --- a/cms/templates/widgets/header.html +++ b/cms/templates/widgets/header.html @@ -12,11 +12,7 @@

- % if settings.FEATURES.get('IS_EDX_DOMAIN', False): - ${settings.STUDIO_NAME} - % else: - ${settings.STUDIO_NAME} - % endif + ${settings.STUDIO_NAME}

% if context_course: diff --git a/common/djangoapps/edxmako/__init__.py b/common/djangoapps/edxmako/__init__.py index 981d640bc089..e7b68f44c393 100644 --- a/common/djangoapps/edxmako/__init__.py +++ b/common/djangoapps/edxmako/__init__.py @@ -13,4 +13,4 @@ # limitations under the License. LOOKUP = {} -from .paths import add_lookup, lookup_template, clear_lookups +from .paths import add_lookup, lookup_template, clear_lookups, save_lookups diff --git a/common/djangoapps/edxmako/management/commands/preprocess_assets.py b/common/djangoapps/edxmako/management/commands/preprocess_assets.py index 43efd4537d78..805981327e89 100644 --- a/common/djangoapps/edxmako/management/commands/preprocess_assets.py +++ b/common/djangoapps/edxmako/management/commands/preprocess_assets.py @@ -8,67 +8,53 @@ template extension (e.g., .mako for Mako templates). Currently Mako is the only template engine supported. """ + import os +import textwrap -from django.core.management.base import NoArgsCommand +from django.core.management.base import BaseCommand from django.conf import settings -from mako.template import Template -import textwrap - -class Command(NoArgsCommand): +class Command(BaseCommand): """ Basic management command to preprocess asset template files. """ help = "Preprocess asset template files to ready them for compilation." - def handle_noargs(self, **options): - """ - Walk over all of the static files directories specified in the - settings file, looking for asset template files (indicated by - a file extension like .mako). - """ - for staticfiles_dir in getattr(settings, "STATICFILES_DIRS", []): - # Cribbed from the django-staticfiles app at: - # https://github.com/jezdez/django-staticfiles/blob/develop/staticfiles/finders.py#L52 - if isinstance(staticfiles_dir, (list, tuple)): - prefix, staticfiles_dir = staticfiles_dir - - # Walk over the current static files directory tree, - # preprocessing files that have a template extension. - for root, dirs, files in os.walk(staticfiles_dir): - for filename in files: - outfile, extension = os.path.splitext(filename) - # We currently only handle Mako templates - if extension == ".mako": - self.__preprocess(os.path.join(root, filename), - os.path.join(root, outfile)) - - def __context(self): - """ - Return a dict that contains all of the available context - variables to the asset template. - """ - # TODO: do we need to include anything else? - # TODO: do this with the django-settings-context-processor - return { - "FEATURES": settings.FEATURES, - "THEME_NAME": getattr(settings, "THEME_NAME", None), - } - - def __preprocess(self, infile, outfile): - """ - Run `infile` through the Mako template engine, storing the - result in `outfile`. - """ - with open(outfile, "w") as _outfile: - _outfile.write(textwrap.dedent("""\ - /* - * This file is dynamically generated and ignored by Git. - * DO NOT MAKE CHANGES HERE. Instead, go edit its template: - * %s - */ - """ % infile)) - _outfile.write(Template(filename=str(infile)).render(env=self.__context())) + def handle(self, *args, **options): + theme_name = getattr(settings, "THEME_NAME", None) + use_custom_theme = settings.FEATURES.get("USE_CUSTOM_THEME", False) + if not use_custom_theme or not theme_name: + # No custom theme, nothing to do! + return + + dest_dir = args[-1] + for source_file in args[:-1]: + self.process_one_file(source_file, dest_dir, theme_name) + + def process_one_file(self, source_file, dest_dir, theme_name): + """Pre-process a .scss file to replace our markers with real code.""" + with open(source_file) as fsource: + original_content = fsource.read() + + content = original_content.replace( + "//", + "@import '{}';".format(theme_name), + ) + + if content != original_content: + if not os.path.exists(dest_dir): + os.makedirs(dest_dir) + dest_file = os.path.join(dest_dir, os.path.basename(source_file)) + with open(dest_file, "w") as fout: + fout.write(textwrap.dedent("""\ + /* + * This file is dynamically generated and ignored by Git. + * DO NOT MAKE CHANGES HERE. Instead, go edit its source: + * {} + */ + \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n + """.format(source_file))) + fout.write(content) diff --git a/common/djangoapps/edxmako/paths.py b/common/djangoapps/edxmako/paths.py index 12cbcdf1d343..18ddb9eafd31 100644 --- a/common/djangoapps/edxmako/paths.py +++ b/common/djangoapps/edxmako/paths.py @@ -3,6 +3,7 @@ """ import hashlib +import contextlib import os import pkg_resources @@ -21,6 +22,9 @@ def __init__(self, *args, **kwargs): super(DynamicTemplateLookup, self).__init__(*args, **kwargs) self.__original_module_directory = self.template_args['module_directory'] + def __repr__(self): + return "<{0.__class__.__name__} {0.directories}>".format(self) + def add_directory(self, directory, prepend=False): """ Add a new directory to the template lookup path. @@ -78,3 +82,26 @@ def lookup_template(namespace, name): Look up a Mako template by namespace and name. """ return LOOKUP[namespace].get_template(name) + + +@contextlib.contextmanager +def save_lookups(): + """ + A context manager to save and restore the Mako template lookup path. + + Useful for testing. + + """ + # Make a copy of the list of directories for each namespace. + namespace_dirs = {namespace: list(look.directories) for namespace, look in LOOKUP.items()} + + try: + yield + finally: + # Get rid of all the lookups. + LOOKUP.clear() + + # Re-create the lookups from our saved list. + for namespace, directories in namespace_dirs.items(): + for directory in directories: + add_lookup(namespace, directory) diff --git a/common/djangoapps/pipeline_mako/templates/static_content.html b/common/djangoapps/pipeline_mako/templates/static_content.html index 213b132168c8..f62abf6635f4 100644 --- a/common/djangoapps/pipeline_mako/templates/static_content.html +++ b/common/djangoapps/pipeline_mako/templates/static_content.html @@ -2,6 +2,9 @@ from staticfiles.storage import staticfiles_storage from pipeline_mako import compressed_css, compressed_js from django.utils.translation import get_language_bidi +from mako.exceptions import TemplateLookupException + +from microsite_configuration import microsite %> <%def name='url(file, raw=False)'><% @@ -73,3 +76,15 @@ }).call(this, require || RequireJS.require); + +<%def name="optional_include_mako(file, with_microsite=False)"><% +# http://stackoverflow.com/q/21219531 +if with_microsite: + file = microsite.get_template_path(file) +try: + tmpl = self.get_template(file) +except TemplateLookupException: + pass +else: + tmpl.render_context(context) +%> diff --git a/common/djangoapps/pipeline_mako/templates/test_exists.html b/common/djangoapps/pipeline_mako/templates/test_exists.html new file mode 100644 index 000000000000..1cc4d19d6ca1 --- /dev/null +++ b/common/djangoapps/pipeline_mako/templates/test_exists.html @@ -0,0 +1,2 @@ +# Only for testing. +

This is test_exists.html

diff --git a/common/djangoapps/pipeline_mako/templates/test_optional_include_mako.html b/common/djangoapps/pipeline_mako/templates/test_optional_include_mako.html new file mode 100644 index 000000000000..b1bb06f80630 --- /dev/null +++ b/common/djangoapps/pipeline_mako/templates/test_optional_include_mako.html @@ -0,0 +1,8 @@ +# A test template for optional_include_mako + +<%namespace name='static' file='static_content.html'/> + +

Welcome to test_optional_include_mako.html

+ +<%static:optional_include_mako file="test_exists.html" /> +<%static:optional_include_mako file="definitely_doesnt_exist.html" /> diff --git a/common/djangoapps/pipeline_mako/tests/__init__.py b/common/djangoapps/pipeline_mako/tests/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/common/djangoapps/pipeline_mako/tests/test_static_content.py b/common/djangoapps/pipeline_mako/tests/test_static_content.py new file mode 100644 index 000000000000..f77a5fc21674 --- /dev/null +++ b/common/djangoapps/pipeline_mako/tests/test_static_content.py @@ -0,0 +1,16 @@ +""" +Tests of pipeline_mako/templates/static_content.html +""" + +import unittest + +from edxmako.shortcuts import render_to_string + + +class TestStaticContent(unittest.TestCase): + """Tests for static_content.html""" + + def test_optional_include_mako(self): + out = render_to_string("test_optional_include_mako.html", {}) + self.assertIn("Welcome to test_optional_include_mako.html", out) + self.assertIn("This is test_exists.html", out) diff --git a/common/lib/xmodule/xmodule/css/capa/display.scss b/common/lib/xmodule/xmodule/css/capa/display.scss index 14ded8073d34..8bd8b551db5b 100644 --- a/common/lib/xmodule/xmodule/css/capa/display.scss +++ b/common/lib/xmodule/xmodule/css/capa/display.scss @@ -111,7 +111,7 @@ iframe[seamless]{ } .inline-error { - color: darken($error-red, 11%); + color: darken($error-color, 11%); } div.problem-progress { @@ -321,7 +321,7 @@ div.problem { display: inline-block; width: 14px; height: 14px; - background: url('../images/unanswered-icon.png') center center no-repeat; + background: url('#{$static-path}/images/unanswered-icon.png') center center no-repeat; } } @@ -330,7 +330,7 @@ div.problem { display: inline-block; width: 25px; height: 20px; - background: url('../images/correct-icon.png') center center no-repeat; + background: url('#{$static-path}/images/correct-icon.png') center center no-repeat; } input { @@ -343,7 +343,7 @@ div.problem { display: inline-block; width: 20px; height: 20px; - background: url('../images/spinner.gif') center center no-repeat; + background: url('#{$static-path}/images/spinner.gif') center center no-repeat; } input { @@ -356,7 +356,7 @@ div.problem { display: inline-block; width: 20px; height: 20px; - background: url('../images/incorrect-icon.png') center center no-repeat; + background: url('#{$static-path}/images/incorrect-icon.png') center center no-repeat; } input { @@ -370,7 +370,7 @@ div.problem { display: inline-block; width: 20px; height: 20px; - background: url('../images/incorrect-icon.png') center center no-repeat; + background: url('#{$static-path}/images/incorrect-icon.png') center center no-repeat; } input { @@ -448,7 +448,7 @@ div.problem { top: 4px; width: 14px; height: 14px; - background: url('../images/unanswered-icon.png') center center no-repeat; + background: url('#{$static-path}/images/unanswered-icon.png') center center no-repeat; } &.processing, &.ui-icon-processing { @@ -457,7 +457,7 @@ div.problem { top: 6px; width: 25px; height: 20px; - background: url('../images/spinner.gif') center center no-repeat; + background: url('#{$static-path}/images/spinner.gif') center center no-repeat; } &.ui-icon-check { @@ -466,7 +466,7 @@ div.problem { top: 3px; width: 25px; height: 20px; - background: url('../images/correct-icon.png') center center no-repeat; + background: url('#{$static-path}/images/correct-icon.png') center center no-repeat; } &.incomplete, &.ui-icon-close { @@ -475,7 +475,7 @@ div.problem { top: 3px; width: 20px; height: 20px; - background: url('../images/incorrect-icon.png') center center no-repeat; + background: url('#{$static-path}/images/incorrect-icon.png') center center no-repeat; } } @@ -503,7 +503,7 @@ div.problem { .grading { margin: 0px 7px 0 0; padding-left: 25px; - background: url('../images/info-icon.png') left center no-repeat; + background: url('#{$static-path}/images/info-icon.png') left center no-repeat; text-indent: 0px; } @@ -967,8 +967,8 @@ div.problem { div.capa_reset { padding: 25px; - border: 1px solid $error-red; - background-color: lighten($error-red, 25%); + border: 1px solid $error-color; + background-color: lighten($error-color, 25%); border-radius: 3px; font-size: 1em; margin-top: $baseline/2; @@ -1097,7 +1097,7 @@ div.problem { .result-errors { margin: ($baseline/4); padding: ($baseline/2) ($baseline/2) ($baseline/2) ($baseline*2); - background: url('../images/incorrect-icon.png') center left no-repeat; + background: url('#{$static-path}/images/incorrect-icon.png') center left no-repeat; li { color: #b00; @@ -1129,7 +1129,7 @@ div.problem { } .result-correct { - background: url('../images/correct-icon.png') left 20px no-repeat; + background: url('#{$static-path}/images/correct-icon.png') left 20px no-repeat; .result-actual-output { color: #090; @@ -1137,7 +1137,7 @@ div.problem { } .result-incorrect { - background: url('../images/incorrect-icon.png') left 20px no-repeat; + background: url('#{$static-path}/images/incorrect-icon.png') left 20px no-repeat; .result-actual-output { color: #B00; @@ -1348,7 +1348,7 @@ div.problem { label.choicetextgroup_show_correct, section.choicetextgroup_show_correct { &:after { margin-left:15px; - content: url('../images/correct-icon.png'); + content: url('#{$static-path}/images/correct-icon.png'); } } @@ -1373,11 +1373,11 @@ div.problem .imageinput.capa_inputtype { } .correct { - background: url('../images/correct-icon.png') center center no-repeat; + background: url('#{$static-path}/images/correct-icon.png') center center no-repeat; } .incorrect { - background: url('../images/incorrect-icon.png') center center no-repeat; + background: url('#{$static-path}/images/incorrect-icon.png') center center no-repeat; } .partially-correct { diff --git a/common/lib/xmodule/xmodule/css/combinedopenended/display.scss b/common/lib/xmodule/xmodule/css/combinedopenended/display.scss index 8da727fecc82..71908f9e5ee0 100644 --- a/common/lib/xmodule/xmodule/css/combinedopenended/display.scss +++ b/common/lib/xmodule/xmodule/css/combinedopenended/display.scss @@ -35,7 +35,7 @@ div.name{ } .inline-error { - color: darken($error-red, 10%); + color: darken($error-color, 10%); } section.combined-open-ended { @@ -178,7 +178,7 @@ section.combined-open-ended-status { float: right; width: 14px; height: 14px; - background: url('../images/unanswered-icon.png') center center no-repeat; + background: url('#{$static-path}/images/unanswered-icon.png') center center no-repeat; } &.correct { @@ -187,7 +187,7 @@ section.combined-open-ended-status { float: right; width: 25px; height: 20px; - background: url('../images/correct-icon.png') center center no-repeat; + background: url('#{$static-path}/images/correct-icon.png') center center no-repeat; } &.incorrect { @@ -196,7 +196,7 @@ section.combined-open-ended-status { float: right; width: 20px; height: 20px; - background: url('../images/incorrect-icon.png') center center no-repeat; + background: url('#{$static-path}/images/incorrect-icon.png') center center no-repeat; } } @@ -302,21 +302,21 @@ div.combined-rubric-container { label.choicegroup_correct { &:before { margin-right: ($baseline*0.75); - content: url('../images/correct-icon.png'); + content: url('#{$static-path}/images/correct-icon.png'); } } label.choicegroup_partialcorrect { &:before { margin-right: ($baseline*0.75); - content: url('../images/partially-correct-icon.png'); + content: url('#{$static-path}/images/partially-correct-icon.png'); } } label.choicegroup_incorrect { &:before { margin-right: ($baseline*0.75); - content: url('../images/incorrect-icon.png'); + content: url('#{$static-path}/images/incorrect-icon.png'); } } @@ -402,7 +402,7 @@ div.result-container { .result-errors { margin: ($baseline/4); padding: ($baseline/2) ($baseline/2) ($baseline/2) ($baseline*2); - background: url('../images/incorrect-icon.png') center left no-repeat; + background: url('#{$static-path}/images/incorrect-icon.png') center left no-repeat; li { color: #B00; @@ -564,7 +564,7 @@ section.open-ended-child { display: inline-block; width: 14px; height: 14px; - background: url('../images/unanswered-icon.png') center center no-repeat; + background: url('#{$static-path}/images/unanswered-icon.png') center center no-repeat; } } @@ -573,7 +573,7 @@ section.open-ended-child { display: inline-block; width: 25px; height: 20px; - background: url('../images/correct-icon.png') center center no-repeat; + background: url('#{$static-path}/images/correct-icon.png') center center no-repeat; } input { @@ -586,7 +586,7 @@ section.open-ended-child { display: inline-block; width: 20px; height: 20px; - background: url('../images/spinner.gif') center center no-repeat; + background: url('#{$static-path}/images/spinner.gif') center center no-repeat; } input { @@ -599,7 +599,7 @@ section.open-ended-child { display: inline-block; width: 20px; height: 20px; - background: url('../images/incorrect-icon.png') center center no-repeat; + background: url('#{$static-path}/images/incorrect-icon.png') center center no-repeat; text-indent: -9999px; } @@ -638,7 +638,7 @@ section.open-ended-child { top: 4px; width: 14px; height: 14px; - background: url('../images/unanswered-icon.png') center center no-repeat; + background: url('#{$static-path}/images/unanswered-icon.png') center center no-repeat; } &.processing, &.ui-icon-processing { @@ -647,7 +647,7 @@ section.open-ended-child { top: 6px; width: 25px; height: 20px; - background: url('../images/spinner.gif') center center no-repeat; + background: url('#{$static-path}/images/spinner.gif') center center no-repeat; } &.correct, &.ui-icon-check { @@ -656,7 +656,7 @@ section.open-ended-child { top: 6px; width: 25px; height: 20px; - background: url('../images/correct-icon.png') center center no-repeat; + background: url('#{$static-path}/images/correct-icon.png') center center no-repeat; } &.incorrect, &.ui-icon-close { @@ -665,7 +665,7 @@ section.open-ended-child { top: 6px; width: 20px; height: 20px; - background: url('../images/incorrect-icon.png') center center no-repeat; + background: url('#{$static-path}/images/incorrect-icon.png') center center no-repeat; } } @@ -703,7 +703,7 @@ section.open-ended-child { .grading { margin: 0 7px 0 0; padding-left: 25px; - background: url('../images/info-icon.png') left center no-repeat; + background: url('#{$static-path}/images/info-icon.png') left center no-repeat; text-indent: 0; } @@ -863,9 +863,9 @@ section.open-ended-child { margin-top: ($baseline/2); margin-bottom: ($baseline/2); padding: 25px; - border: 1px solid $error-red; + border: 1px solid $error-color; border-radius: 3px; - background-color: lighten($error-red, 25%); + background-color: lighten($error-color, 25%); font-size: 1em; } diff --git a/common/lib/xmodule/xmodule/css/problem/edit.scss b/common/lib/xmodule/xmodule/css/problem/edit.scss index 692985ec6255..ac6f3f90ff0b 100644 --- a/common/lib/xmodule/xmodule/css/problem/edit.scss +++ b/common/lib/xmodule/xmodule/css/problem/edit.scss @@ -110,7 +110,7 @@ width: 26px; height: 21px; vertical-align: middle; - background: url(../images/problem-editor-icons.png) no-repeat; + background: url('#{$static-path}/images/problem-editor-icons.png') no-repeat; } .problem-editor-icon.heading1 { diff --git a/common/lib/xmodule/xmodule/css/video/display.scss b/common/lib/xmodule/xmodule/css/video/display.scss index 63d3a38844a3..5f531435bfcb 100644 --- a/common/lib/xmodule/xmodule/css/video/display.scss +++ b/common/lib/xmodule/xmodule/css/video/display.scss @@ -280,7 +280,7 @@ div.video { a.ui-slider-handle { @extend %ui-fake-link; @include transform(scale(.7, 1.3) translate3d(-80%, -15%, 0)); - background: $pink url(../images/slider-handle.png) center center no-repeat; + background: $pink url('#{$static-path}/images/slider-handle.png') center center no-repeat; background-size: 50%; border: 1px solid darken($pink, 20%); border-radius: 50%; @@ -314,7 +314,7 @@ div.video { .video_control { @extend %video-button; float: left; - background-image: url('../images/vcr.png'); + background-image: url('#{$static-path}/images/vcr.png'); background-position: 15px 15px ; background-repeat: no-repeat; border-left: none; @@ -445,7 +445,7 @@ div.video { div.speeds { &.is-opened { .speed-button { - background-image: url('../images/open-arrow.png'); + background-image: url('#{$static-path}/images/open-arrow.png'); } } @@ -460,7 +460,7 @@ div.video { .speed-button { @extend %video-button; @include clearfix(); - background-image: url('../images/closed-arrow.png'); + background-image: url('#{$static-path}/images/closed-arrow.png'); background-position: 10px center; background-repeat: no-repeat; min-width: 116px; @@ -515,14 +515,14 @@ div.video { &.is-muted { & > a { - background-image: url('../images/mute.png'); + background-image: url('#{$static-path}/images/mute.png'); } } & > a { @extend %video-button; @include clearfix(); - background-image: url('../images/volume.png'); + background-image: url('#{$static-path}/images/volume.png'); background-position: 10px center; background-repeat: no-repeat; width: 30px; @@ -559,7 +559,7 @@ div.video { a.ui-slider-handle { @extend %ui-fake-link; @include transition(height $tmg-s2 ease-in-out 0s, width $tmg-s2 ease-in-out 0s); - background: $pink url(../images/slider-handle.png) center center no-repeat; + background: $pink url('#{$static-path}/images/slider-handle.png') center center no-repeat; background-size: 50%; border: 1px solid darken($pink, 20%); border-radius: 15px; @@ -578,7 +578,7 @@ div.video { a.add-fullscreen { @extend %video-button; - background: url(../images/fullscreen.png) center no-repeat; + background: url('#{$static-path}/images/fullscreen.png') center no-repeat; border-left: none; float: left; padding: 0 11px; @@ -588,7 +588,7 @@ div.video { a.quality-control { @extend %video-button; - background: url(../images/hd.png) center no-repeat; + background: url('#{$static-path}/images/hd.png') center no-repeat; border-left: none; float: left; padding: 0 11px; @@ -610,7 +610,7 @@ div.video { @extend %video-button; @include transition(none); box-shadow: inset 1px 0 0 #555; - background: url('../images/cc.png') center no-repeat; + background: url('#{$static-path}/images/cc.png') center no-repeat; border-left: none; border-right: none; padding: 0 11px; diff --git a/common/lib/xmodule/xmodule/static_content.py b/common/lib/xmodule/xmodule/static_content.py index 3d58ac235088..deed93e0c5a0 100755 --- a/common/lib/xmodule/xmodule/static_content.py +++ b/common/lib/xmodule/xmodule/static_content.py @@ -95,10 +95,10 @@ def _write_styles(selector, output_root, classes): for class_ in classes: css_imports[class_].add(fragment_name) - module_styles_lines = [] - module_styles_lines.append("@import 'bourbon/bourbon';") - module_styles_lines.append("@import 'bourbon/addons/button';") - module_styles_lines.append("@import 'assets/anims';") + module_styles_lines = [ + "@import 'bourbon/bourbon';", + "@import 'base/variables';", + ] for class_, fragment_names in css_imports.items(): module_styles_lines.append("""{selector}.xmodule_{class_} {{""".format( class_=class_, selector=selector diff --git a/common/test/acceptance/pages/lms/learner_profile.py b/common/test/acceptance/pages/lms/learner_profile.py index 4b2f08f1eb3b..87325be1a71a 100644 --- a/common/test/acceptance/pages/lms/learner_profile.py +++ b/common/test/acceptance/pages/lms/learner_profile.py @@ -175,7 +175,7 @@ def profile_has_default_image(self): """ self.wait_for_field('image') default_links = self.q(css='.image-frame').attrs('src') - return 'default-profile' in default_links[0] if default_links else False + return 'profiles/default' in default_links[0] if default_links else False def mouse_hover(self, element): """ diff --git a/conf/locale/babel_mako.cfg b/conf/locale/babel_mako.cfg index f017d73afa4f..b1722ade50bc 100644 --- a/conf/locale/babel_mako.cfg +++ b/conf/locale/babel_mako.cfg @@ -28,3 +28,5 @@ input_encoding = utf-8 input_encoding = utf-8 [mako: themes/**.html] input_encoding = utf-8 +[mako: themes/**.html] +input_encoding = utf-8 diff --git a/lms/djangoapps/branding/__init__.py b/lms/djangoapps/branding/__init__.py index e8fa35ee2220..efe6c93876ff 100644 --- a/lms/djangoapps/branding/__init__.py +++ b/lms/djangoapps/branding/__init__.py @@ -70,4 +70,4 @@ def get_logo_url(): elif university: return staticfiles_storage.url('images/{uni}-on-edx-logo.png'.format(uni=university)) else: - return staticfiles_storage.url('images/default-theme/logo.png') + return staticfiles_storage.url('images/logo.png') diff --git a/lms/djangoapps/courseware/tests/test_comp_theming.py b/lms/djangoapps/courseware/tests/test_comp_theming.py new file mode 100644 index 000000000000..d2bc70123816 --- /dev/null +++ b/lms/djangoapps/courseware/tests/test_comp_theming.py @@ -0,0 +1,73 @@ +"""Tests of comprehensive theming.""" + +from django.conf import settings +from django.test import TestCase + +from path import path # pylint: disable=no-name-in-module +import staticfiles + +from openedx.core.djangoapps.theming.test_util import with_comp_theme +from openedx.core.lib.tempdir import mkdtemp_clean + + +class TestComprehensiveTheming(TestCase): + """Test comprehensive theming.""" + + def setUp(self): + super(TestComprehensiveTheming, self).setUp() + + # Clear the internal staticfiles caches, to get test isolation. + staticfiles.finders._finders.clear() # pylint: disable=protected-access + + @with_comp_theme(settings.REPO_ROOT / 'themes/red-theme') + def test_red_footer(self): + resp = self.client.get('/') + self.assertEqual(resp.status_code, 200) + # This string comes from footer.html + self.assertContains(resp, "super-ugly") + # This string comes from header.html + self.assertContains(resp, "This file is only for demonstration, and is horrendous!") + + def test_theme_outside_repo(self): + # Need to create a temporary theme, and defer decorating the function + # until it is done, which leads to this strange nested-function style + # of test. + + # Make a temp directory as a theme. + tmp_theme = path(mkdtemp_clean()) + template_dir = tmp_theme / "lms/templates" + template_dir.makedirs() + with open(template_dir / "footer.html", "w") as footer: + footer.write("
TEMPORARY THEME
") + + @with_comp_theme(tmp_theme) + def do_the_test(self): + """A function to do the work so we can use the decorator.""" + resp = self.client.get('/') + self.assertEqual(resp.status_code, 200) + self.assertContains(resp, "TEMPORARY THEME") + + do_the_test(self) + + def test_theme_adjusts_staticfiles_search_path(self): + # Test that a theme adds itself to the staticfiles search path. + before_finders = list(settings.STATICFILES_FINDERS) + before_dirs = list(settings.STATICFILES_DIRS) + + @with_comp_theme(settings.REPO_ROOT / 'themes/red-theme') + def do_the_test(self): + """A function to do the work so we can use the decorator.""" + self.assertEqual(list(settings.STATICFILES_FINDERS), before_finders) + self.assertEqual(settings.STATICFILES_DIRS[0], settings.REPO_ROOT / 'themes/red-theme/lms/static') + self.assertEqual(settings.STATICFILES_DIRS[1:], before_dirs) + + do_the_test(self) + + def test_default_logo_image(self): + result = staticfiles.finders.find('images/logo.png') + self.assertEqual(result, settings.REPO_ROOT / 'lms/static/images/logo.png') + + @with_comp_theme(settings.REPO_ROOT / 'themes/red-theme') + def test_overridden_logo_image(self): + result = staticfiles.finders.find('images/logo.png') + self.assertEqual(result, settings.REPO_ROOT / 'themes/red-theme/lms/static/images/logo.png') diff --git a/lms/djangoapps/courseware/tests/test_footer.py b/lms/djangoapps/courseware/tests/test_footer.py index b6623491381e..0a14ee18604a 100644 --- a/lms/djangoapps/courseware/tests/test_footer.py +++ b/lms/djangoapps/courseware/tests/test_footer.py @@ -3,13 +3,14 @@ edx.org uses an edx footer but other instances use an Open edX footer. """ -from mock import patch from nose.plugins.attrib import attr from django.conf import settings from django.test import TestCase from django.test.utils import override_settings +from openedx.core.djangoapps.theming.test_util import with_is_edx_domain + @attr('shard_1') class TestFooter(TestCase): @@ -36,26 +37,26 @@ class TestFooter(TestCase): "youtube": "https://www.youtube.com/" } + @with_is_edx_domain(True) def test_edx_footer(self): """ Verify that the homepage, when accessed at edx.org, has the edX footer """ - with patch.dict('django.conf.settings.FEATURES', {"IS_EDX_DOMAIN": True}): - resp = self.client.get('/') - self.assertEqual(resp.status_code, 200) - self.assertContains(resp, 'footer-edx-v3') + resp = self.client.get('/') + self.assertEqual(resp.status_code, 200) + self.assertContains(resp, 'footer-edx-v3') + @with_is_edx_domain(False) def test_openedx_footer(self): """ Verify that the homepage, when accessed at something other than edx.org, has the Open edX footer """ - with patch.dict('django.conf.settings.FEATURES', {"IS_EDX_DOMAIN": False}): - resp = self.client.get('/') - self.assertEqual(resp.status_code, 200) - self.assertContains(resp, 'footer-openedx') + resp = self.client.get('/') + self.assertEqual(resp.status_code, 200) + self.assertContains(resp, 'footer-openedx') - @patch.dict(settings.FEATURES, {'IS_EDX_DOMAIN': True}) + @with_is_edx_domain(True) @override_settings( SOCIAL_MEDIA_FOOTER_NAMES=SOCIAL_MEDIA_NAMES, SOCIAL_MEDIA_FOOTER_URLS=SOCIAL_MEDIA_URLS diff --git a/lms/envs/aws.py b/lms/envs/aws.py index ef3d1b3193d1..cdc68616b44e 100644 --- a/lms/envs/aws.py +++ b/lms/envs/aws.py @@ -230,6 +230,7 @@ # Theme overrides THEME_NAME = ENV_TOKENS.get('THEME_NAME', None) +COMP_THEME_DIR = path(ENV_TOKENS.get('COMP_THEME_DIR', COMP_THEME_DIR)) # Marketing link overrides MKTG_URL_LINK_MAP.update(ENV_TOKENS.get('MKTG_URL_LINK_MAP', {})) @@ -679,10 +680,7 @@ PROFILE_IMAGE_SECRET_KEY = AUTH_TOKENS.get('PROFILE_IMAGE_SECRET_KEY', PROFILE_IMAGE_SECRET_KEY) PROFILE_IMAGE_MAX_BYTES = ENV_TOKENS.get('PROFILE_IMAGE_MAX_BYTES', PROFILE_IMAGE_MAX_BYTES) PROFILE_IMAGE_MIN_BYTES = ENV_TOKENS.get('PROFILE_IMAGE_MIN_BYTES', PROFILE_IMAGE_MIN_BYTES) -if FEATURES['IS_EDX_DOMAIN']: - PROFILE_IMAGE_DEFAULT_FILENAME = 'images/edx-theme/default-profile' -else: - PROFILE_IMAGE_DEFAULT_FILENAME = ENV_TOKENS.get('PROFILE_IMAGE_DEFAULT_FILENAME', PROFILE_IMAGE_DEFAULT_FILENAME) +PROFILE_IMAGE_DEFAULT_FILENAME = 'images/profiles/default' # EdxNotes config diff --git a/lms/envs/common.py b/lms/envs/common.py index a0e5c474a030..5d53cbbd1759 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -195,7 +195,7 @@ # Enable URL that shows information about the status of variuous services 'ENABLE_SERVICE_STATUS': False, - # Toggle to indicate use of a custom theme + # Toggle to indicate use of the Stanford theming system 'USE_CUSTOM_THEME': False, # Don't autoplay videos for students @@ -451,6 +451,9 @@ DATA_DIR = COURSES_ROOT +# comprehensive theming system +COMP_THEME_DIR = "" + # TODO: Remove the rest of the sys.path modification here and in cms/envs/common.py sys.path.append(REPO_ROOT) sys.path.append(PROJECT_ROOT / 'djangoapps') @@ -1832,6 +1835,9 @@ 'staticfiles', 'static_replace', + # Theming + 'openedx.core.djangoapps.theming', + # Our courseware 'circuit', 'courseware', @@ -2588,7 +2594,7 @@ 'base_url': os.path.join(MEDIA_URL, 'profile-images/'), }, } -PROFILE_IMAGE_DEFAULT_FILENAME = 'images/default-theme/default-profile' +PROFILE_IMAGE_DEFAULT_FILENAME = 'images/profiles/default' PROFILE_IMAGE_DEFAULT_FILE_EXTENSION = 'png' # This secret key is used in generating unguessable URLs to users' # profile images. Once it has been set, changing it will make the diff --git a/lms/startup.py b/lms/startup.py index 809432a3aee3..6869f9082859 100644 --- a/lms/startup.py +++ b/lms/startup.py @@ -34,7 +34,7 @@ def run(): add_mimetypes() if settings.FEATURES.get('USE_CUSTOM_THEME', False): - enable_theme() + enable_stanford_theme() if settings.FEATURES.get('USE_MICROSITES', False): enable_microsites() @@ -69,7 +69,7 @@ def add_mimetypes(): mimetypes.add_type('application/font-woff', '.woff') -def enable_theme(): +def enable_stanford_theme(): """ Enable the settings for a custom theme, whose files should be stored in ENV_ROOT/themes/THEME_NAME (e.g., edx_all/themes/stanford). @@ -77,7 +77,7 @@ def enable_theme(): # Workaround for setting THEME_NAME to an empty # string which is the default due to this ansible # bug: https://github.com/ansible/ansible/issues/4812 - if settings.THEME_NAME == "": + if getattr(settings, "THEME_NAME", "") == "": settings.THEME_NAME = None return diff --git a/lms/static/certificates/sass/_components.scss b/lms/static/certificates/sass/_components.scss index 5333b6c66010..3653fa4e239f 100644 --- a/lms/static/certificates/sass/_components.scss +++ b/lms/static/certificates/sass/_components.scss @@ -494,7 +494,7 @@ } .accomplishment-rendering { - background: palette(grayscale, white-t) url('../images/bg-distinguished.png') center no-repeat; + background: palette(grayscale, white-t) url('#{$static-path}/images/bg-distinguished.png') center no-repeat; background-size: 65%; .deco-corner-tl { diff --git a/lms/static/images/default-theme/logo-large.png b/lms/static/images/logo-large.png similarity index 100% rename from lms/static/images/default-theme/logo-large.png rename to lms/static/images/logo-large.png diff --git a/lms/static/images/default-theme/logo.png b/lms/static/images/logo.png similarity index 100% rename from lms/static/images/default-theme/logo.png rename to lms/static/images/logo.png diff --git a/lms/static/images/default-theme/default-profile_120.png b/lms/static/images/profiles/default_120.png similarity index 100% rename from lms/static/images/default-theme/default-profile_120.png rename to lms/static/images/profiles/default_120.png diff --git a/lms/static/images/default-theme/default-profile_30.png b/lms/static/images/profiles/default_30.png similarity index 100% rename from lms/static/images/default-theme/default-profile_30.png rename to lms/static/images/profiles/default_30.png diff --git a/lms/static/images/default-theme/default-profile_50.png b/lms/static/images/profiles/default_50.png similarity index 100% rename from lms/static/images/default-theme/default-profile_50.png rename to lms/static/images/profiles/default_50.png diff --git a/lms/static/images/default-theme/default-profile_500.png b/lms/static/images/profiles/default_500.png similarity index 100% rename from lms/static/images/default-theme/default-profile_500.png rename to lms/static/images/profiles/default_500.png diff --git a/lms/static/sass/base/_base.scss b/lms/static/sass/base/_base.scss index 9e0520033a70..e6d9665fe813 100644 --- a/lms/static/sass/base/_base.scss +++ b/lms/static/sass/base/_base.scss @@ -179,7 +179,7 @@ span.edx { width: 20px; height: 20px; margin-left: -($baseline/2); - background: url(../images/spinner.gif) no-repeat; + background: url('#{$static-path}/images/spinner.gif') no-repeat; } mark { @@ -205,7 +205,7 @@ mark { width: 27px; height: 24px; margin-right: ($baseline*0.75); - background: url(../images/large-white-error-icon.png) no-repeat; + background: url('#{$static-path}/images/large-white-error-icon.png') no-repeat; } .inner-wrapper { diff --git a/lms/static/sass/base/_extends.scss b/lms/static/sass/base/_extends.scss index 5d48734d8e32..5c0f70b6454f 100644 --- a/lms/static/sass/base/_extends.scss +++ b/lms/static/sass/base/_extends.scss @@ -68,7 +68,7 @@ //Styles for Error messages %error-message-colors { - background: $error-red; + background: $error-color; border: 1px solid rgb(202, 17, 17); color: rgb(143, 14, 14); } diff --git a/lms/static/sass/base/_font_face.scss b/lms/static/sass/base/_font_face.scss index 25b6d1596eb3..b5beb9e85426 100644 --- a/lms/static/sass/base/_font_face.scss +++ b/lms/static/sass/base/_font_face.scss @@ -3,9 +3,9 @@ @font-face { font-family: 'Open Sans'; src: - url('../fonts/OpenSans/OpenSans-Light-webfont.woff2') format('woff2'), - url('../fonts/OpenSans/OpenSans-Light-webfont.woff') format('woff'), - url('../fonts/OpenSans/OpenSans-Light-webfont.ttf') format('truetype'); + url('#{$static-path}/fonts/OpenSans/OpenSans-Light-webfont.woff2') format('woff2'), + url('#{$static-path}/fonts/OpenSans/OpenSans-Light-webfont.woff') format('woff'), + url('#{$static-path}/fonts/OpenSans/OpenSans-Light-webfont.ttf') format('truetype'); font-weight: 300; font-style: normal; } @@ -13,9 +13,9 @@ @font-face { font-family: 'Open Sans'; src: - url('../fonts/OpenSans/OpenSans-LightItalic-webfont.woff2') format('woff2'), - url('../fonts/OpenSans/OpenSans-LightItalic-webfont.woff') format('woff'), - url('../fonts/OpenSans/OpenSans-LightItalic-webfont.ttf') format('truetype'); + url('#{$static-path}/fonts/OpenSans/OpenSans-LightItalic-webfont.woff2') format('woff2'), + url('#{$static-path}/fonts/OpenSans/OpenSans-LightItalic-webfont.woff') format('woff'), + url('#{$static-path}/fonts/OpenSans/OpenSans-LightItalic-webfont.ttf') format('truetype'); font-weight: 300; font-style: italic; } @@ -23,9 +23,9 @@ @font-face { font-family: 'Open Sans'; src: - url('../fonts/OpenSans/OpenSans-Regular-webfont.woff2') format('woff2'), - url('../fonts/OpenSans/OpenSans-Regular-webfont.woff') format('woff'), - url('../fonts/OpenSans/OpenSans-Regular-webfont.ttf') format('truetype'); + url('#{$static-path}/fonts/OpenSans/OpenSans-Regular-webfont.woff2') format('woff2'), + url('#{$static-path}/fonts/OpenSans/OpenSans-Regular-webfont.woff') format('woff'), + url('#{$static-path}/fonts/OpenSans/OpenSans-Regular-webfont.ttf') format('truetype'); font-weight: 400; font-style: normal; } @@ -33,9 +33,9 @@ @font-face { font-family: 'Open Sans'; src: - url('../fonts/OpenSans/OpenSans-Italic-webfont.woff2') format('woff2'), - url('../fonts/OpenSans/OpenSans-Italic-webfont.woff') format('woff'), - url('../fonts/OpenSans/OpenSans-Italic-webfont.ttf') format('truetype'); + url('#{$static-path}/fonts/OpenSans/OpenSans-Italic-webfont.woff2') format('woff2'), + url('#{$static-path}/fonts/OpenSans/OpenSans-Italic-webfont.woff') format('woff'), + url('#{$static-path}/fonts/OpenSans/OpenSans-Italic-webfont.ttf') format('truetype'); font-weight: 400; font-style: italic; } @@ -43,9 +43,9 @@ @font-face { font-family: 'Open Sans'; src: - url('../fonts/OpenSans/OpenSans-Semibold-webfont.woff2') format('woff2'), - url('../fonts/OpenSans/OpenSans-Semibold-webfont.woff') format('woff'), - url('../fonts/OpenSans/OpenSans-Semibold-webfont.ttf') format('truetype'); + url('#{$static-path}/fonts/OpenSans/OpenSans-Semibold-webfont.woff2') format('woff2'), + url('#{$static-path}/fonts/OpenSans/OpenSans-Semibold-webfont.woff') format('woff'), + url('#{$static-path}/fonts/OpenSans/OpenSans-Semibold-webfont.ttf') format('truetype'); font-weight: 600; font-style: normal; } @@ -53,9 +53,9 @@ @font-face { font-family: 'Open Sans'; src: - url('../fonts/OpenSans/OpenSans-SemiboldItalic-webfont.woff2') format('woff2'), - url('../fonts/OpenSans/OpenSans-SemiboldItalic-webfont.woff') format('woff'), - url('../fonts/OpenSans/OpenSans-SemiboldItalic-webfont.ttf') format('truetype'); + url('#{$static-path}/fonts/OpenSans/OpenSans-SemiboldItalic-webfont.woff2') format('woff2'), + url('#{$static-path}/fonts/OpenSans/OpenSans-SemiboldItalic-webfont.woff') format('woff'), + url('#{$static-path}/fonts/OpenSans/OpenSans-SemiboldItalic-webfont.ttf') format('truetype'); font-weight: 600; font-style: italic; } @@ -63,9 +63,9 @@ @font-face { font-family: 'Open Sans'; src: - url('../fonts/OpenSans/OpenSans-Bold-webfont.woff2') format('woff2'), - url('../fonts/OpenSans/OpenSans-Bold-webfont.woff') format('woff'), - url('../fonts/OpenSans/OpenSans-Bold-webfont.ttf') format('truetype'); + url('#{$static-path}/fonts/OpenSans/OpenSans-Bold-webfont.woff2') format('woff2'), + url('#{$static-path}/fonts/OpenSans/OpenSans-Bold-webfont.woff') format('woff'), + url('#{$static-path}/fonts/OpenSans/OpenSans-Bold-webfont.ttf') format('truetype'); font-weight: 700; font-style: normal; } @@ -73,9 +73,9 @@ @font-face { font-family: 'Open Sans'; src: - url('../fonts/OpenSans/OpenSans-BoldItalic-webfont.woff2') format('woff2'), - url('../fonts/OpenSans/OpenSans-BoldItalic-webfont.woff') format('woff'), - url('../fonts/OpenSans/OpenSans-BoldItalic-webfont.ttf') format('truetype'); + url('#{$static-path}/fonts/OpenSans/OpenSans-BoldItalic-webfont.woff2') format('woff2'), + url('#{$static-path}/fonts/OpenSans/OpenSans-BoldItalic-webfont.woff') format('woff'), + url('#{$static-path}/fonts/OpenSans/OpenSans-BoldItalic-webfont.ttf') format('truetype'); font-weight: 700; font-style: italic; } diff --git a/lms/static/sass/base/_variables.scss b/lms/static/sass/base/_variables.scss index ebd490dd6af5..6f139bec0b09 100644 --- a/lms/static/sass/base/_variables.scss +++ b/lms/static/sass/base/_variables.scss @@ -1,89 +1,77 @@ // lms - utilities - variables // ==================== -// BASE -$baseline: 20px; +// #CONFIG: paths and configuration +// #UNITS: Basic units of measurement +// #GRID: Grid and layout variables +// #COLORS: Base, palette and theme color definitions + application +// #TYPOGRAPHY: Font definitions and scales +// #DEPTH: UI depth-based scale +// #SPACING: General UI spacing variables and scale +// #FORMS: form field/interaction variables +// #TIMING: Event timing variables +// #APPLICATIONS: Applying configuration +// #DEPRECATED: sunsetted and not to be used variables + +// ---------------------------- +// #CONFIG +// ---------------------------- +$static-path: '..' !default; + + +// ---------------------------- +// #UNITS +// ---------------------------- +$baseline: 20px !default; + + +// ---------------------------- +// #GRID +// ---------------------------- +$gw-column: 80px !default; +$gw-gutter: 20px !default; +$fg-column: $gw-column !default; +$fg-gutter: $gw-gutter !default; +$fg-max-columns: 12 !default; +$fg-max-width: 1400px !default; +$fg-min-width: 810px !default; + + +// ---------------------------- +// #COLORS +// ---------------------------- +$transparent: rgba(0,0,0,0) !default; // used when color value is needed for UI width/transitions but element is transparent + +$black: rgb(0,0,0) !default; +$black-t0: rgba($black, 0.125) !default; +$black-t1: rgba($black, 0.25) !default; +$black-t2: rgba($black, 0.5) !default; +$black-t3: rgba($black, 0.75) !default; + +$white: rgb(255,255,255) !default; +$white-t0: rgba($white, 0.125) !default; +$white-t1: rgba($white, 0.25) !default; +$white-t2: rgba($white, 0.5) !default; +$white-t3: rgba($white, 0.75) !default; + +$gray: rgb(118,118,118) !default; +$gray-l1: tint($gray,20%) !default; +$gray-l2: tint($gray,40%) !default; +$gray-l3: tint($gray,60%) !default; +$gray-l4: tint($gray,80%) !default; +$gray-l5: tint($gray,90%) !default; +$gray-l6: tint($gray,95%) !default; +$gray-l7: tint($gray,99%) !default; +$gray-d1: shade($gray,20%) !default; +$gray-d2: shade($gray,40%) !default; +$gray-d3: shade($gray,60%) !default; +$gray-d4: shade($gray,80%) !default; -// ==================== - -// LAYOUT: grid -$gw-column: 80px; -$gw-gutter: 20px; -$fg-column: $gw-column; -$fg-gutter: $gw-gutter; -$fg-max-columns: 12; -$fg-max-width: 1400px; -$fg-min-width: 810px; - -// ==================== - -// FONTS -$sans-serif: 'Open Sans', $verdana, sans-serif; -$monospace: Monaco, 'Bitstream Vera Sans Mono', 'Lucida Console', monospace; -$body-font-family: $sans-serif; -$serif: $georgia; - -// FONT-WEIGHTS -$font-light: 300; -$font-regular: 400; -$font-semibold: 600; -$font-bold: 700; - -// ==================== - -// MISC: base fonts/colors -$body-font-size: em(14); -$body-line-height: golden-ratio(.875em, 1); -$base-font-color: rgb(60,60,60); -$baseFontColor: rgb(60,60,60); -$base-font-color: rgb(60,60,60); -$lighter-base-font-color: rgb(100,100,100); -$very-light-text: rgb(255,255,255); // #ffffff - -// ==================== -// TIMING - used for animation/transition mixin syncing -$tmg-s3: 3.0s; -$tmg-s2: 2.0s; -$tmg-s1: 1.0s; -$tmg-avg: 0.75s; -$tmg-f1: 0.50s; -$tmg-f2: 0.25s; -$tmg-f3: 0.125s; - -// ==================== +$blue: rgb(0, 120, 176); +$yellow: rgb(255, 252, 221); -// COLORS - utility -$transparent: rgba(0,0,0,0); // used when color value is needed for UI width/transitions but element is transparent - -// COLORS -$black: rgb(0,0,0); // #000000; -$black-t0: rgba($black, 0.125); -$black-t1: rgba($black, 0.25); -$black-t2: rgba($black, 0.5); -$black-t3: rgba($black, 0.75); - -$white: rgb(255,255,255); // #FFFFFF; -$white-t0: rgba($white, 0.125); -$white-t1: rgba($white, 0.25); -$white-t2: rgba($white, 0.5); -$white-t3: rgba($white, 0.75); - -$gray: rgb(118,118,118); // #767676 AA compliant -$gray-l1: tint($gray,20%); // #989898 -$gray-l2: tint($gray,40%); // #b2b2b2 -$gray-l3: tint($gray,60%); // #cbcbcb -$gray-l4: tint($gray,80%); // #e5e5e5 -$gray-l5: tint($gray,90%); // #f2f2f2 -$gray-l6: tint($gray,95%); // #f8f8f8 -$gray-l7: tint($gray,99%); // #fdfdfd -$gray-d1: shade($gray,20%); // #656565 -$gray-d2: shade($gray,40%); // #4c4c4c -$gray-d3: shade($gray,60%); // #323232 -$gray-d4: shade($gray,80%); // #191919 - - -$pink: rgb(182,37,103); // #b72567; +$pink: rgb(182,37,103); $pink-l1: tint($pink,20%); $pink-l2: tint($pink,40%); $pink-l3: tint($pink,60%); @@ -100,7 +88,7 @@ $pink-u1: desaturate($pink,15%); $pink-u2: desaturate($pink,30%); $pink-u3: desaturate($pink,45%); -$red: rgb(178, 6, 16); // #b20610; +$red: rgb(178, 6, 16); $red-l1: tint($red,20%); $red-l2: tint($red,40%); $red-l3: tint($red,60%); @@ -117,7 +105,7 @@ $red-u1: desaturate($red,15%); $red-u2: desaturate($red,30%); $red-u3: desaturate($red,45%); -$green: rgb(37, 184, 90); // #25b85a; +$green: rgb(37, 184, 90); $green-l1: tint($green,20%); $green-l2: tint($green,40%); $green-l3: tint($green,60%); @@ -198,84 +186,81 @@ $ui-notification-height: ($baseline*10); // ==================== -// COLORS: social platforms +// social platforms $twitter-blue: #55ACEE; $facebook-blue: #3B5998; $linkedin-blue: #0077B5; -// ==================== - -// TODO: both blue and yellow variables differ from CMS rgb value, need to confirm change to CMS variable is ok in current platform uses before switching. -//$yellow: rgb(255, 252, 221); - -// ==================== - -// COLORS: old variables -// DEPRECATED: use colors in lists above -$error-red: rgb(253, 87, 87); -$danger-red: rgb(212, 64, 64); -$light-gray: rgb(221, 221, 221); -$dark-gray: rgb(51, 51, 51); -$border-color: rgb(200, 200, 200); -$sidebar-color: rgb(246, 246, 246); -$outer-border-color: rgb(170, 170, 170); -$light-gray: rgb(221,221,221); // #dddddd - -// ==================== - -// used by descriptor css -// DEPRECATED: use colors in lists above -$lightGrey: rgb(237,241,245); // #edf1f5 -$darkGrey: rgb(136,145,161); // #8891a1 -$lightGrey1: $gray-l3; -$blue-d1: shade($blue,20%); -$blue-d2: shade($blue,40%); -$blue-d4: shade($blue,80%); - -// ==================== - -// edx.org marketing site variables -$m-gray: rgb(138,140,143); // #8A8C8F -$m-gray-l1: rgb(151,153,155); // #97999B -$m-gray-l2: rgb(164,166,168); // #A4A6A8 -$m-gray-l3: rgb(177,178,180); // #B1B2B4 -$m-gray-l4: rgb(245,245,245); // #F5F5F5 -$m-gray-d1: rgb(111, 112, 116); // #6f7074 -$m-gray-d2: rgb(112,114,118); // #707276 -$m-gray-d3: rgb(100,102,104); // #646668 -$m-gray-d4: rgb(5,5,5); // #050505 +// shadows +$shadow: rgba(0,0,0,0.2) !default; +$shadow-l1: rgba(0,0,0,0.1) !default; +$shadow-l2: rgba(0,0,0,0.05) !default; +$shadow-d1: rgba(0,0,0,0.4) !default; +$shadow-d2: rgba($black, 0.6) !default; + +// system feedback-based colors +$error-color: rgb(253, 87, 87) !default; +$warning-color: rgb(181,42,103) !default; +$confirm-color: rgb(0, 136, 1) !default; +$active-color: $blue !default; +$highlight-color: rgb(255,255,0) !default; +$alert-color: rgb(212, 64, 64) !default; +$warning-color: rgb(237, 189, 60) !default; +$success-color: rgb(37, 184, 90) !default; + +// newer color variables +$dark-gray1: rgb(74,74,74); +$light-gray1: rgb(242,242,242); +$light-gray2: rgb(171,171,171); +$light-gray3: rgb(249,249,249); +$dark-gray2: rgb(151,151,151); +$blue1: rgb(74,144,226); +$blue2: rgb(0,161,229); +$green1: rgb(97,161,46); +$red1: rgb(208,2,27); + +// edx-specific: marketing site variables +$m-gray: rgb(138,140,143); //C8F +$m-gray-l1: rgb(151,153,155); +$m-gray-l2: rgb(164,166,168); +$m-gray-l3: rgb(177,178,180); +$m-gray-l4: rgb(245,245,245); +$m-gray-d1: rgb(111, 112, 116); +$m-gray-d2: rgb(112,114,118); +$m-gray-d3: rgb(100,102,104); +$m-gray-d4: rgb(5,5,5); $m-gray-t0: rgba($m-gray,0.125); $m-gray-t1: rgba($m-gray,0.25); $m-gray-t2: rgba($m-gray,0.50); $m-gray-t3: rgba($m-gray,0.75); -$m-blue: rgb(26,161,222); // #1AA1DE -$m-blue-l1: rgb(43,172,230); // #2BACE6 -$m-blue-l2: rgb(66,181,233); // #42B5E9 -$m-blue-l3: rgb(89,190,236); // #59BEEC +$m-blue: rgb(26,161,222); +$m-blue-l1: rgb(43,172,230); +$m-blue-l2: rgb(66,181,233); +$m-blue-l3: rgb(89,190,236); $m-blue-l4: tint($m-blue,90%); $m-blue-l5: tint($m-blue,95%); $m-blue-l6: #4bb4fb; -$m-blue-d1: rgb(23,144,199); // #1790C7 +$m-blue-d1: rgb(23,144,199); $m-blue-d2: $blue; -$m-blue-d3: rgb(18,111,154); // #126F9A -$m-blue-d4: rgb(10,74,103); // #0A4A67 -$m-blue-d5: rgb(0,158,231); // #009EE7 +$m-blue-d3: rgb(18,111,154); +$m-blue-d4: rgb(10,74,103); +$m-blue-d5: rgb(0,158,231); $m-blue-d6: #256A97; $m-blue-t0: rgba($m-blue,0.125); $m-blue-t1: rgba($m-blue,0.25); $m-blue-t2: rgba($m-blue,0.50); $m-blue-t3: rgba($m-blue,0.75); -$m-pink: rgb(181,42,103); // #B52A67 -$m-pink-l1: rgb(202,47,115); //#CA2F73 -$m-pink-l2: rgb(211,63,128); //#D33F80 -$m-pink-l3: rgb(215,84,142); //#D7548E +$m-pink: rgb(181,42,103); +$m-pink-l1: rgb(202,47,115); +$m-pink-l2: rgb(211,63,128); +$m-pink-l3: rgb(215,84,142); $m-pink-l4: tint($m-pink,75%); $m-pink-l5: tint($m-pink,85%); -$m-pink-d1: rgb(160,37,91); // #A0255B -$m-pink-d2: rgb(140,32,79); // #8C204F -$m-pink-d3: rgb(119,28,68); // #771C44 +$m-pink-d1: rgb(160,37,91); +$m-pink-d2: rgb(140,32,79); +$m-pink-d3: rgb(119,28,68); $m-green: rgb(0, 136, 1); $m-green-s1: rgb(96, 188, 97); @@ -293,138 +278,100 @@ $m-green-t1: rgba($m-green,0.25); $m-green-t2: rgba($m-green,0.50); $m-green-t3: rgba($m-green,0.75); -// ==================== - -// SHADOWS -$shadow: rgba(0,0,0,0.2); -$shadow-l1: rgba(0,0,0,0.1); -$shadow-l2: rgba(0,0,0,0.05); -$shadow-d1: rgba(0,0,0,0.4); -$shadow-d2: rgba($black, 0.6); - -// ==================== - -$m-base-font-size: em(15); - -$base-font-color: rgb(60,60,60); -$baseFontColor: rgb(60,60,60); -$lighter-base-font-color: rgb(100,100,100); -$text-color: $dark-gray; - -$dark-trans-bg: rgba(0, 0, 0, .75); - -$body-bg: rgb(250,250,250); -$container-bg: $white; -$header-image: linear-gradient(-90deg, rgba(255,255,255, 1), rgba(230,230,230, 0.9)); -$header-bg: $white; -$courseware-header-image: linear-gradient(top, rgb(255,255,255), rgb(238,238,238)); -$courseware-header-bg: transparent; -$footer-bg: $white; -$courseware-footer-border: none; -$courseware-footer-shadow: none; -$courseware-footer-margin: 0px; -$courseware-border-bottom-color: rgb(68,162,222); // #44a2de -$courseware-button-border-color: rgb(230,230,230); // #e6e6e6 -$courseware-hover-color: rgb(51,52,53); // #333435 -$courseware-navigation-color: $blue; - -// ==================== - -// STATE: verified +// edx-specific: verified $verified-color-lvl1: $m-green; $verified-color-lvl2: $m-green-l1; $verified-color-lvl3: $m-green-l2; $verified-color-lvl4: $m-green-l3; $verified-color-lvl5: $m-green-l4; -// STATE: professional ed +// edx-specific: professional ed $professional-color-lvl1: $m-pink; $professional-color-lvl2: $m-pink-l1; $professional-color-lvl3: $m-pink-l2; $professional-color-lvl4: $m-pink-l3; $professional-color-lvl5: $m-pink-l4; -// STATE: honor code +// edx-specific: honor code $honorcode-color-lvl1: rgb(50, 165, 217); $honorcode-color-lvl2: tint($honorcode-color-lvl1, 33%); -// STATE: audit -$audit-color-lvl1: $light-gray; +// edx-specific: audit +$audit-color-lvl1: rgb(221, 221, 221); $audit-color-lvl2: tint($audit-color-lvl1, 33%); -// STATE: credit +// edx-specific: credit $credit-color-base: rgb(244,195,0); // accessible with black text -// ==================== - -// ACTIONS: general -$button-bg-image: linear-gradient(rgb(255,255,255) 0%, rgb(250,250,250) 50%, rgb(237,237,237) 50%, rgb(220,220,220) 100%); -$button-bg-color: transparent; -$button-bg-hover-color: $white; - -// ACTIONS: primary -$action-primary-bg: $m-blue-d3; -$action-primary-fg: $white; -$action-primary-shadow: $m-blue-d4; - -// ACTIONS: primary - focused - hover/active pseudo states -$action-primary-focused-bg: $m-blue-d1; -$action-primary-focused-fg: $white; - -// ACTIONS: primary - current or active navigation item -$action-primary-active-bg: $m-blue; -$action-primary-active-fg: $m-blue-d3; -$action-primary-active-shadow: $m-blue-d2; -$action-primary-active-focused-fg: $m-blue-d4; -$action-primary-active-focused-shadow: $m-blue-d3; - -// ACTIONS: disabled -$action-primary-disabled-bg: $m-gray-d3; -$action-prmary-disabled-fg: $white; - -// ACTIONS: secondary -$action-secondary-bg: $m-pink; -$action-secondary-fg: $white; -$action-secondary-shadow: $m-pink-d2; - -// ACTIONS: secondary - focused - hover/active pseudo states -$action-secondary-focused-bg: $m-pink-l3; -$action-secondary-focused-fg: $white; - -// ACTIONS: secondary - current or active navigation item -$action-secondary-active-bg: $m-pink-l2; -$action-secondary-active-fg: $m-pink-d1; -$action-secondary-active-shadow: $m-pink-d1; -$action-secondary-active-focused-fg: $m-pink-d3; -$action-secondary-active-focused-shadow: $m-pink-d2; - -// ACTIONS: secondary - disabled -$action-secondary-disabled-bg: $m-gray-d3; -$action-secondary-disabled-fg: $white; - -// HEADER: graphic-based page titles -$header-graphic-super-color: $m-blue-d1; -$header-graphic-sub-color: $m-gray-d2; - -// State-based colors -$error-color: $error-red; -$warning-color: $m-pink; -$confirm-color: $m-green; -$active-color: $blue; -$highlight-color: rgb(255,255,0); - -// Notifications -$notify-banner-bg-1: rgb(56,56,56); -$notify-banner-bg-2: rgb(136,136,136); -$notify-banner-bg-3: $shadow-l2; - -$alert-color: rgb(212, 64, 64); //rich red -$warning-color: rgb(237, 189, 60); //rich yellow -$success-color: rgb(37, 184, 90); //rich green - -// ==================== -// MISC: visual horizontal rules +// ---------------------------- +// #TYPOGRAPHY +// ---------------------------- +$sans-serif: 'Open Sans', $verdana, sans-serif !default; +$monospace: Monaco, 'Bitstream Vera Sans Mono', 'Lucida Console', monospace !default; +$body-font-family: $sans-serif !default; +$serif: $georgia !default; + +// newer variables/standards +$f-serif: 'Bree Serif', Georgia, Cambria, 'Times New Roman', Times, serif !default; +$f-sans-serif: 'Open Sans','Helvetica Neue', Helvetica, Arial, sans-serif !default; +$f-monospace: 'Bitstream Vera Sans Mono', Consolas, Courier, monospace !default; + +$font-light: 300 !default; +$font-regular: 400 !default; +$font-semibold: 600 !default; +$font-bold: 700 !default; + +$m-base-font-size: em(15) !default; + + +// ---------------------------- +// #DEPTH +// ---------------------------- + + +// ---------------------------- +// #TIMING +// ---------------------------- +$tmg-s3: 3.0s !default; +$tmg-s2: 2.0s !default; +$tmg-s1: 1.0s !default; +$tmg-avg: 0.75s !default; +$tmg-f1: 0.50s !default; +$tmg-f2: 0.25s !default; +$tmg-f3: 0.125s !default; + + +// ---------------------------- +// #FORMS +// ---------------------------- +$form-bg-color: $white !default; + +// ---------------------------- +// #APPLICATIONS +// ---------------------------- +// font sizes +$body-font-size: em(14) !default; +$body-line-height: golden-ratio(.875em, 1) !default; + +$base-font-color: rgb(60,60,60) !default; +$baseFontColor: $base-font-color; + +$lighter-base-font-color: rgb(100,100,100) $base-font-color; +$very-light-text: rgb(255,255,255) !default; +$text-color: rgb(51, 51, 51) !default; + +// borders +$border-color-1: rgb(190,190,190) !default; +$border-color-2: rgb(200,200,200) !default; +$border-color-3: rgb(100,100,100) !default; +$border-color-4: rgb(252,252,252) !default; +$border-color-l1: $m-gray-l1 !default; +$border-color-l2: $m-gray-l2 !default; +$border-color-l3: $m-gray-l3 !default; +$border-color-l4: $m-gray-l4 !default; + +// visual horizontal rules $faded-hr-image-1: linear-gradient(180deg, rgba(200,200,200, 0) 0%, rgba(200,200,200, 1) 50%, rgba(200,200,200, 0)); $faded-hr-image-2: linear-gradient(180deg, rgba(200,200,200, 0) 0%, rgba(200,200,200, 1)); $faded-hr-image-3: linear-gradient(180deg, rgba(200,200,200, 1) 0%, rgba(200,200,200, 0)); @@ -432,116 +379,147 @@ $faded-hr-image-4: linear-gradient(180deg, rgba(240,240,240, 0) 0%, rgba(240,240 $faded-hr-image-5: linear-gradient(180deg, rgba(255,255,255, 0) 0%, rgba(255,255,255, 0.8) 50%, rgba(255,255,255, 0)); $faded-hr-image-6: linear-gradient(90deg, rgba(255,255,255, 0) 0%, rgba(255,255,255, 0.6) 50%, rgba(255,255,255, 0)); -// MISC: dashboard -$dashboard-profile-header-image: linear-gradient(-90deg, rgb(255,255,255), rgb(245,245,245)); -$dashboard-profile-header-color: transparent; -$dashboard-profile-color: rgb(252,252,252); -$dot-color: $light-gray; -$dashboard-course-cover-border: $light-gray; - -// MISC: course assets -$content-wrapper-bg: $white; -$course-bg-color: #f2f2f2; -$course-bg-image: url(../images/bg-texture.png); -$account-content-wrapper-bg: shade($body-bg, 2%); -$course-profile-bg: rgb(245,245,245); -$course-header-bg: rgba(255,255,255, 0.93); - -// MISC: course background texture -//$course-bg-image: url(../images/bg-texture.png); - -// MISC: borders -$border-color-1: rgb(190,190,190); -$border-color-2: rgb(200,200,200); -$border-color-3: rgb(100,100,100); -$border-color-4: rgb(252,252,252); -$border-color-l1: $m-gray-l1; -$border-color-l2: $m-gray-l2; -$border-color-l3: $m-gray-l3; -$border-color-l4: $m-gray-l4; - -// MISC: links and buttons -$link-color: $blue; -$link-color-d1: $blue; -$link-hover: $blue-l1; // from our Pattern Library http://ux.edx.org/elements/colors/ -$site-status-color: $pink; -$button-color: $blue; -$button-archive-color: rgb(238,238,238); // #eeeeee - -// MISC: shadow, form, modal -$shadow-color: $blue; -$form-bg-color: $white; -$modal-bg-color: rgb(245,245,245); - -// MISC: sidebar -$sidebar-chapter-bg-top: rgba(255, 255, 255, .5); -$sidebar-chapter-bg-bottom: rgba(255, 255, 255, 0); -$sidebar-chapter-bg: rgb(246,246,246); // #f6f6f6 -$sidebar-active-image: linear-gradient(top, rgb(230,230,230), rgb(214,214,214)); - -// TOP HEADER IMAGE MARGIN -$header_image_margin: -69px; - -//FOOTER MARGIN -$footer_margin: ($baseline/4) 0 ($baseline*1.5) 0; - -// ==================== - -// VIEWS: homepage -$homepage__header--gradient__color--alpha: lighten($gray, 15%); -$homepage__header--gradient__color--bravo: saturate($gray, 30%); -$homepage__header--background: lighten($gray, 15%); - -// VIEWS: homepage and courses -$course-card-height: ($baseline*18); -$course-image-height: ($baseline*8); -$course-info-height: ($baseline*10); -$course-title-height: ($baseline*3.6); - -// ==================== - -// IMAGES: backgrounds -$homepage-bg-image: none; - -$login-banner-image: url(../images/edx-theme/edx-background-banner-account.png); -$register-banner-image: url(../images/edx-theme/edx-background-banner-account.png); -$passwordreset-banner-image: url(../images/edx-theme/edx-background-banner-account.png); - -$video-thumb-url: '../images/homepage-hero-video-thumb.jpg'; - -// ==================== - -// SPLINT: new standards - -// SPLINT: fonts -$f-serif: 'Bree Serif', Georgia, Cambria, 'Times New Roman', Times, serif; -$f-sans-serif: 'Open Sans','Helvetica Neue', Helvetica, Arial, sans-serif; -$f-monospace: 'Bitstream Vera Sans Mono', Consolas, Courier, monospace; - -// Header specific sans-serif -$header-sans-serif: 'Open Sans', Arial, Helvetica, sans-serif; - -// SPLINT: colors - -$msg-bg: $action-primary-bg; +// notifications +$notify-banner-bg-1: rgb(56,56,56) !default; +$notify-banner-bg-2: rgb(136,136,136) !default; +$notify-banner-bg-3: $shadow-l2 !default; +$msg-bg: $m-blue-d3 !default; + +// actions +$button-bg-image: linear-gradient(rgb(255,255,255) 0%, rgb(250,250,250) 50%, rgb(237,237,237) 50%, rgb(220,220,220) 100%) !default; +$button-bg-color: transparent !default; +$button-bg-hover-color: $white !default; + +// action - primary +$action-primary-bg: $m-blue-d3 !default; +$action-primary-fg: $white !default; +$action-primary-shadow: $m-blue-d4 !default; +$action-primary-focused-bg: $m-blue-d1 !default; +$action-primary-focused-fg: $white !default; +$action-primary-active-bg: $m-blue !default; +$action-primary-active-fg: $m-blue-d3 !default; +$action-primary-active-shadow: $m-blue-d2 !default; +$action-primary-active-focused-fg: $m-blue-d4 !default; +$action-primary-active-focused-shadow: $m-blue-d3 !default; +$action-primary-disabled-bg: $m-gray-d3 !default; +$action-prmary-disabled-fg: $white !default; + +// action - secondary +$action-secondary-bg: $m-pink !default; +$action-secondary-fg: $white !default; +$action-secondary-shadow: $m-pink-d2 !default; +$action-secondary-focused-bg: $m-pink-l3 !default; +$action-secondary-focused-fg: $white !default; +$action-secondary-active-bg: $m-pink-l2 !default; +$action-secondary-active-fg: $m-pink-d1 !default; +$action-secondary-active-shadow: $m-pink-d1 !default; +$action-secondary-active-focused-fg: $m-pink-d3 !default; +$action-secondary-active-focused-shadow: $m-pink-d2 !default; +$action-secondary-disabled-bg: $m-gray-d3 !default; +$action-secondary-disabled-fg: $white !default; + +// actions - misc +$link-color: $blue !default; +$link-color-d1: $blue !default; +$link-hover: $blue-l1 !default; // from our Pattern Library http://ux.edx.org/elements/colors/ +$site-status-color: $pink !default; +$button-color: $blue !default; +$button-archive-color: rgb(238,238,238) !default; // #eeeeee + +// larger, random elements +$dark-trans-bg: rgba(0, 0, 0, .75); +$body-bg: rgb(250,250,250) !default; -$dark-gray1: rgb(74,74,74); // # -$light-gray1: rgb(242,242,242); // #f2f2f2 -$light-gray2: rgb(171,171,171); // #ababab -$light-gray3: rgb(249,249,249); // #f9f9f9 -$dark-gray2: rgb(151,151,151); // #979797 -$blue1: rgb(74,144,226); // #4A90E2 -$blue2: rgb(0,161,229); // #00A1E5 -$green1: rgb(97,161,46); // #61A12E -$red1: rgb(208,2,27); // #D0021B +$container-bg: $white !default; -// +case: search/result highlight -// -------------------- -$result-highlight-color-base: rgba($highlight-color, 0.25); +// header +$header-image: linear-gradient(-90deg, rgba(255,255,255, 1), rgba(230,230,230, 0.9)) !default; +$header-bg: $white !default; +$header-graphic-super-color: $m-blue-d1; +$header-graphic-sub-color: $m-gray-d2; +$header-sans-serif: 'Open Sans', Arial, Helvetica, sans-serif !default; +$header_image_margin: -69px !default; + +// footer +$footer-bg: $white !default; +$footer_margin: ($baseline/4) 0 ($baseline*1.5) 0 !default; + +// modal +$shadow-color: $blue !default; +$modal-bg-color: rgb(245,245,245) !default; + +// courseware elements +$courseware-header-image: linear-gradient(top, rgb(255,255,255), rgb(238,238,238)) !default; +$courseware-header-bg: transparent !default; +$courseware-footer-border: none !default; +$courseware-footer-shadow: none !default; +$courseware-footer-margin: 0px !default; +$courseware-border-bottom-color: rgb(68,162,222) !default; +$courseware-button-border-color: rgb(230,230,230) !default; +$courseware-hover-color: rgb(51,52,53) !default; +$courseware-navigation-color: $blue !default; + +// homepage, onboarding, and course discovery +$homepage__header--gradient__color--alpha: lighten($gray, 15%) !default; +$homepage__header--gradient__color--bravo: saturate($gray, 30%) !default; +$homepage__header--background: lighten($gray, 15%) !default; +$course-card-height: ($baseline*18) !default; +$course-image-height: ($baseline*8) !default; +$course-info-height: ($baseline*10) !default; +$course-title-height: ($baseline*3.6) !default; +$homepage-bg-image: none !default; +$login-banner-image: url('#{$static-path}/images/edx-theme/edx-background-banner-account.png') !default; +$register-banner-image: url('#{$static-path}/images/edx-theme/edx-background-banner-account.png') !default; +$passwordreset-banner-image: url('#{$static-path}/images/edx-theme/edx-background-banner-account.png') !default; + +$video-thumb-url: '#{$static-path}/images/homepage-hero-video-thumb.jpg' !default; + +// dashboard elements +$dashboard-profile-header-image: linear-gradient(-90deg, rgb(255,255,255), rgb(245,245,245)) !default; +$dashboard-profile-header-color: transparent !default; +$dashboard-profile-color: rgb(252,252,252) !default; +$dot-color: rgb(221, 221, 221) !default; +$dashboard-course-cover-border: rgb(221, 221, 221) !default; + +// course elements +$content-wrapper-bg: $white !default; +$course-bg-color: #f2f2f2 !default; +$course-bg-image: url('#{$static-path}/images/bg-texture.png') !default; +$account-content-wrapper-bg: shade($body-bg, 2%) !default; +$course-profile-bg: rgb(245,245,245) !default; +$course-header-bg: rgba(255,255,255, 0.93) !default; + +// search/listing results +$result-highlight-color-base: rgba($highlight-color, 0.25) !default; + +// sidebar +$sidebar-chapter-bg-top: rgba(255, 255, 255, .5); +$sidebar-chapter-bg-bottom: rgba(255, 255, 255, 0); +$sidebar-chapter-bg: rgb(246,246,246) !default; +$sidebar-active-image: linear-gradient(top, rgb(230,230,230), rgb(214,214,214)) !default; + + +// student notes +$student-notes-highlight-color-base: saturate($yellow, 65%) !default; +$student-notes-highlight-color: tint($student-notes-highlight-color-base, 50%) !default; +$student-notes-highlight-color-focus: $student-notes-highlight-color-base !default; + +// ---------------------------- +// #DEPRECATED +// ---------------------------- +$danger-red: rgb(212, 64, 64) !default; +$light-gray: rgb(221, 221, 221) !default; +$dark-gray: rgb(51, 51, 51) !default; +$border-color: rgb(200, 200, 200) !default; +$sidebar-color: rgb(246, 246, 246) !default; +$outer-border-color: rgb(170, 170, 170); +$light-gray: rgb(221,221,221) !default; -// +feature: student notes -// -------------------- -$student-notes-highlight-color-base: saturate($yellow, 65%); -$student-notes-highlight-color: tint($student-notes-highlight-color-base, 50%); -$student-notes-highlight-color-focus: $student-notes-highlight-color-base; +// used by descriptor css +$lightGrey: rgb(237,241,245) !default; +$darkGrey: rgb(136,145,161) !default; +$lightGrey1: $gray-l3 !default; +$blue-d1: shade($blue,20%); +$blue-d2: shade($blue,40%); +$blue-d4: shade($blue,80%); diff --git a/lms/static/sass/course-rtl.scss b/lms/static/sass/course-rtl.scss index f34a72937aac..9282339cdb74 100644 --- a/lms/static/sass/course-rtl.scss +++ b/lms/static/sass/course-rtl.scss @@ -7,8 +7,8 @@ @import 'vendor/bi-app/bi-app-rtl'; // set the layout for right to left languages @import 'base/reset'; -@import 'base/font_face'; @import 'base/variables'; +@import 'base/font_face'; @import 'base/mixins'; diff --git a/lms/static/sass/course.scss b/lms/static/sass/course.scss index a265ddf8f30b..fc666a978d06 100644 --- a/lms/static/sass/course.scss +++ b/lms/static/sass/course.scss @@ -7,8 +7,8 @@ @import 'vendor/bi-app/bi-app-ltr'; // set the layout for left to right languages @import 'base/reset'; -@import 'base/font_face'; @import 'base/variables'; +@import 'base/font_face'; @import 'base/mixins'; diff --git a/lms/static/sass/course/_gradebook.scss b/lms/static/sass/course/_gradebook.scss index e2113318714b..9bd921dd6c94 100644 --- a/lms/static/sass/course/_gradebook.scss +++ b/lms/static/sass/course/_gradebook.scss @@ -20,7 +20,7 @@ div.gradebook-wrapper { @include box-sizing(border-box); border-radius: 13px; border: 1px solid $table-border-color; - background: url(../images/search-icon.png) no-repeat 9px center $gray-l6; + background: url('#{$static-path}/images/search-icon.png') no-repeat 9px center $gray-l6; font-family: $sans-serif; font-size: 11px; box-shadow: 0 1px 4px rgba(0, 0, 0, .12) inset; diff --git a/lms/static/sass/course/_info.scss b/lms/static/sass/course/_info.scss index 6518d908f3e1..0bbca1d75710 100644 --- a/lms/static/sass/course/_info.scss +++ b/lms/static/sass/course/_info.scss @@ -33,7 +33,7 @@ div.info-wrapper { h2 { font-size: $body-font-size; font-weight: bold; - background: url('../images/calendar-icon.png') 0 center no-repeat; + background: url('#{$static-path}/images/calendar-icon.png') 0 center no-repeat; padding-left: $baseline; } @@ -183,7 +183,7 @@ div.info-wrapper { } div.hitarea { - background-image: url('../images/treeview-default.gif') no-repeat; + background-image: url('#{$static-path}/images/treeview-default.gif') no-repeat; display: block; height: 100%; margin-left: 0; diff --git a/lms/static/sass/course/_textbook.scss b/lms/static/sass/course/_textbook.scss index b24a3a52a26b..d2c3d3a04835 100755 --- a/lms/static/sass/course/_textbook.scss +++ b/lms/static/sass/course/_textbook.scss @@ -72,7 +72,7 @@ div.book-wrapper { } div.hitarea { - background-image: url('../images/treeview-default.gif'); + background-image: url('#{$static-path}/images/treeview-default.gif'); position: relative; top: 4px; @@ -150,7 +150,7 @@ div.book-wrapper { left: 0; a { - background-image: url('../images/textbook/textbook-left.png'); + background-image: url('#{$static-path}/images/textbook/textbook-left.png'); } } @@ -158,7 +158,7 @@ div.book-wrapper { right: 0; a { - background-image: url('../images/textbook/textbook-right.png'); + background-image: url('#{$static-path}/images/textbook/textbook-right.png'); } } @@ -207,7 +207,7 @@ div.book-wrapper { padding: 0; a { - background-image: url('../images/slide-right-icon.png'); + background-image: url('#{$static-path}/images/slide-right-icon.png'); } h2 { diff --git a/lms/static/sass/course/base/_extends.scss b/lms/static/sass/course/base/_extends.scss index 55b46fb60420..b309e677da49 100644 --- a/lms/static/sass/course/base/_extends.scss +++ b/lms/static/sass/course/base/_extends.scss @@ -152,7 +152,7 @@ h1.top-header { position: relative; a { - background: #f6f6f6 url('../images/slide-left-icon.png') center center no-repeat; + background: #f6f6f6 url('#{$static-path}/images/slide-left-icon.png') center center no-repeat; border: 1px solid #D3D3D3; border-radius: 3px 0 0 3px; height: 16px; diff --git a/lms/static/sass/course/courseware/_amplifier.scss b/lms/static/sass/course/courseware/_amplifier.scss index 0abb8b261a1c..dea469df02f8 100644 --- a/lms/static/sass/course/courseware/_amplifier.scss +++ b/lms/static/sass/course/courseware/_amplifier.scss @@ -231,7 +231,7 @@ section.tool-wrapper { } .ui-slider-handle { - background: lighten( #586e75, 5% ) url('../images/amplifier-slider-handle.png') center no-repeat; + background: lighten( #586e75, 5% ) url('#{$static-path}/images/amplifier-slider-handle.png') center no-repeat; border: 1px solid darken(#002b36, 8%); box-shadow: inset 0 1px 0 lighten( #586e75, 20% ); margin-top: -.3em; diff --git a/lms/static/sass/course/courseware/_courseware.scss b/lms/static/sass/course/courseware/_courseware.scss index 06ac2a00b20f..cb2509b0b478 100644 --- a/lms/static/sass/course/courseware/_courseware.scss +++ b/lms/static/sass/course/courseware/_courseware.scss @@ -614,7 +614,7 @@ div.course-wrapper { div.staff_actions { p.error { - color: $error-red + color: $error-color } p.success { color: $success-color; @@ -667,7 +667,7 @@ div.course-wrapper { header#open_close_accordion { a { - background-image: url('../images/slide-right-icon.png'); + background-image: url('#{$static-path}/images/slide-right-icon.png'); } } diff --git a/lms/static/sass/course/discussion/_form-wmd-toolbar.scss b/lms/static/sass/course/discussion/_form-wmd-toolbar.scss index 2caf6cd9286b..45db5c108a0b 100644 --- a/lms/static/sass/course/discussion/_form-wmd-toolbar.scss +++ b/lms/static/sass/course/discussion/_form-wmd-toolbar.scss @@ -52,7 +52,7 @@ margin-left: ($baseline/4); margin-right: ($baseline/4); position: absolute; - background-image: url(../images/wmd-buttons.png); + background-image: url('#{$static-path}/images/wmd-buttons.png'); background-repeat: no-repeat; background-position: 0px 0px; display: inline-block; diff --git a/lms/static/sass/course/instructor/_instructor_2.scss b/lms/static/sass/course/instructor/_instructor_2.scss index bef79f255673..0a29b01f2f02 100644 --- a/lms/static/sass/course/instructor/_instructor_2.scss +++ b/lms/static/sass/course/instructor/_instructor_2.scss @@ -137,12 +137,12 @@ .request-response-error { margin: 0; padding-bottom: ($baseline); - color: $error-red; + color: $error-color; } .display-errors { line-height: 3em; - color: $error-red; + color: $error-color; } .slickgrid { diff --git a/lms/static/sass/course/modules/_calculator.scss b/lms/static/sass/course/modules/_calculator.scss index ee8e13952645..311d2d3d54fa 100644 --- a/lms/static/sass/course/modules/_calculator.scss +++ b/lms/static/sass/course/modules/_calculator.scss @@ -17,7 +17,7 @@ .calc { @include transition(background-color $tmg-f2 ease-in-out 0s); - background: url("../images/calc-icon.png") $black-t1 no-repeat center; + background: url("#{$static-path}/images/calc-icon.png") $black-t1 no-repeat center; border-bottom: 0; color: $white; float: right; @@ -33,7 +33,7 @@ } &.closed { - background-image: url("../images/close-calc-icon.png"); + background-image: url("#{$static-path}/images/close-calc-icon.png"); background-color: $black; top: -36px; } @@ -155,7 +155,7 @@ height: 35px; width: 35px; border: none; - background: url("../images/info-icon.png") center center no-repeat; + background: url("#{$static-path}/images/info-icon.png") center center no-repeat; color: $white; &:focus { diff --git a/lms/static/sass/course/wiki/_wiki.scss b/lms/static/sass/course/wiki/_wiki.scss index 22347d73461e..03ba78d48e4c 100644 --- a/lms/static/sass/course/wiki/_wiki.scss +++ b/lms/static/sass/course/wiki/_wiki.scss @@ -100,7 +100,7 @@ section.wiki { width: 180px; height: 27px; padding: 0 15px 0 35px; - background: url(../images/search-icon.png) no-repeat 9px center $gray-l6; + background: url('#{$static-path}/images/search-icon.png') no-repeat 9px center $gray-l6; border: 1px solid #c8c8c8; border-radius: 14px; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.12) inset; diff --git a/lms/static/sass/discussion/_discussion.scss b/lms/static/sass/discussion/_discussion.scss index 09181d001221..b8894925d8b7 100644 --- a/lms/static/sass/discussion/_discussion.scss +++ b/lms/static/sass/discussion/_discussion.scss @@ -417,7 +417,7 @@ body.discussion { .discussion-article { position: relative; min-height: 500px; - background-image: url(../images/bg-texture.png); + background-image: url('#{$static-path}/images/bg-texture.png'); a { word-wrap: break-word; @@ -598,7 +598,7 @@ body.discussion { background: transparent; span { - background-image: url(../images/wmd-buttons-transparent.png); + background-image: url('#{$static-path}/images/wmd-buttons-transparent.png'); } } } @@ -720,7 +720,7 @@ body.discussion { } .loading-animation { - background-image: url(../images/spinner.gif); + background-image: url('#{$static-path}/images/spinner.gif'); } .discussion-show { @@ -742,7 +742,7 @@ body.discussion { @include margin-right(6px); width: 21px; height: 19px; - background: url(../images/show-hide-discussion-icon.png) no-repeat; + background: url('#{$static-path}/images/show-hide-discussion-icon.png') no-repeat; background-position: -21px 0; } } diff --git a/lms/static/sass/discussion/views/_create-edit-post.scss b/lms/static/sass/discussion/views/_create-edit-post.scss index 70c710b4a68c..5260f4d79f58 100644 --- a/lms/static/sass/discussion/views/_create-edit-post.scss +++ b/lms/static/sass/discussion/views/_create-edit-post.scss @@ -180,7 +180,7 @@ margin-bottom: $baseline; border-radius: 3px; padding: 0; - background: $error-red; + background: $error-color; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3) inset, 0 1px 0 rgba(255, 255, 255, .2); color: $white; list-style: none; @@ -188,7 +188,7 @@ .post-error { padding: ($baseline/2) $baseline 12px 45px; border-bottom: 1px solid $red; - background: url(../images/white-error-icon.png) no-repeat 15px 14px; + background: url('#{$static-path}/images/white-error-icon.png') no-repeat 15px 14px; &:last-child { border-bottom: none; diff --git a/lms/static/sass/elements/_creative-commons.scss b/lms/static/sass/elements/_creative-commons.scss index d14351f83ba8..dc3a5a0b05ea 100644 --- a/lms/static/sass/elements/_creative-commons.scss +++ b/lms/static/sass/elements/_creative-commons.scss @@ -1,10 +1,10 @@ @font-face { font-family: 'CreativeCommons'; - src: url('../fonts/CreativeCommons/cc.eot'); - src: url('../fonts/CreativeCommons/cc.eot#iefix') format('embedded-opentype'), - url('../fonts/CreativeCommons/cc.woff') format('woff'), - url('../fonts/CreativeCommons/cc.ttf') format('truetype'), - url('../fonts/CreativeCommons/cc.svg#CreativeCommons') format('svg'); + src: url('#{$static-path}/fonts/CreativeCommons/cc.eot'); + src: url('#{$static-path}/fonts/CreativeCommons/cc.eot#iefix') format('embedded-opentype'), + url('#{$static-path}/fonts/CreativeCommons/cc.woff') format('woff'), + url('#{$static-path}/fonts/CreativeCommons/cc.ttf') format('truetype'), + url('#{$static-path}/fonts/CreativeCommons/cc.svg#CreativeCommons') format('svg'); font-weight: normal; font-style: normal; } diff --git a/lms/static/sass/lms-course-rtl.scss b/lms/static/sass/lms-course-rtl.scss new file mode 100644 index 000000000000..47c0dcda71c4 --- /dev/null +++ b/lms/static/sass/lms-course-rtl.scss @@ -0,0 +1,13 @@ +@import 'bourbon/bourbon'; +@import 'vendor/bi-app/bi-app-rtl'; // set the layout for right to left languages + +@import 'base/reset'; +@import 'base/variables'; +@import 'base/font_face'; +@import 'base/mixins'; + +// This comment is used by preprocess_assets.py to include resources from a +// theme, for old-style deprecated theming. +// + +@import 'build-course'; // shared app style assets/rendering diff --git a/lms/static/sass/lms-course-rtl.scss.mako b/lms/static/sass/lms-course-rtl.scss.mako deleted file mode 100644 index 2e96d2e36f53..000000000000 --- a/lms/static/sass/lms-course-rtl.scss.mako +++ /dev/null @@ -1,22 +0,0 @@ -@import 'bourbon/bourbon'; -@import 'vendor/bi-app/bi-app-rtl'; // set the layout for right to left languages - -@import 'base/reset'; -@import 'base/font_face'; -@import 'base/variables'; -@import 'base/mixins'; - -## THEMING -## ------- -## Set up this file to import an edX theme library if the environment -## indicates that a theme should be used. The assumption is that the -## theme resides outside of this main edX repository, in a directory -## called themes//, with its base Sass file in -## themes//static/sass/_.scss. That one entry -## point can be used to @import in as many other things as needed. -% if env["FEATURES"].get("USE_CUSTOM_THEME", False): - // import theme's Sass overrides - @import '${env.get('THEME_NAME')}'; -% endif - -@import 'build-course'; // shared app style assets/rendering diff --git a/lms/static/sass/lms-course.scss b/lms/static/sass/lms-course.scss new file mode 100644 index 000000000000..53ecb202e2d7 --- /dev/null +++ b/lms/static/sass/lms-course.scss @@ -0,0 +1,13 @@ +@import 'bourbon/bourbon'; +@import 'vendor/bi-app/bi-app-ltr'; // set the layout for left to right languages + +@import 'base/reset'; +@import 'base/variables'; +@import 'base/font_face'; +@import 'base/mixins'; + +// This comment is used by preprocess_assets.py to include resources from a +// theme, for old-style deprecated theming. +// + +@import 'build-course'; // shared app style assets/rendering diff --git a/lms/static/sass/lms-course.scss.mako b/lms/static/sass/lms-course.scss.mako deleted file mode 100644 index e4fbab34b347..000000000000 --- a/lms/static/sass/lms-course.scss.mako +++ /dev/null @@ -1,22 +0,0 @@ -@import 'bourbon/bourbon'; -@import 'vendor/bi-app/bi-app-ltr'; // set the layout for left to right languages - -@import 'base/reset'; -@import 'base/font_face'; -@import 'base/variables'; -@import 'base/mixins'; - -## THEMING -## ------- -## Set up this file to import an edX theme library if the environment -## indicates that a theme should be used. The assumption is that the -## theme resides outside of this main edX repository, in a directory -## called themes//, with its base Sass file in -## themes//static/sass/_.scss. That one entry -## point can be used to @import in as many other things as needed. -% if env["FEATURES"].get("USE_CUSTOM_THEME", False): - // import theme's Sass overrides - @import '${env.get('THEME_NAME')}'; -% endif - -@import 'build-course'; // shared app style assets/rendering diff --git a/lms/static/sass/lms-footer-rtl.scss b/lms/static/sass/lms-footer-rtl.scss new file mode 100644 index 000000000000..218aa1f9649f --- /dev/null +++ b/lms/static/sass/lms-footer-rtl.scss @@ -0,0 +1,26 @@ +// Footer for OpenEdX (right-to-left) +// ================================== + +// libs and resets *do not edit* +@import 'bourbon/bourbon'; // lib - bourbon +@import 'vendor/bi-app/bi-app-rtl'; // set the layout for right to left languages + +// base - utilities +@import 'base/variables'; +@import 'base/mixins'; + +// This comment is used by preprocess_assets.py to include resources from a +// theme, for old-style deprecated theming. +// + +footer#footer-openedx { + @import 'base/reset'; + @import 'base/extends'; + @import 'base/base'; +} + +// base - elements +@import 'elements/typography'; + +// shared - platform +@import 'shared/footer'; diff --git a/lms/static/sass/lms-footer-rtl.scss.mako b/lms/static/sass/lms-footer-rtl.scss.mako deleted file mode 100644 index cc91fab37995..000000000000 --- a/lms/static/sass/lms-footer-rtl.scss.mako +++ /dev/null @@ -1,35 +0,0 @@ -// Footer for OpenEdX (right-to-left) -// ================================== - -// libs and resets *do not edit* -@import 'bourbon/bourbon'; // lib - bourbon -@import 'vendor/bi-app/bi-app-rtl'; // set the layout for right to left languages - -// base - utilities -@import 'base/variables'; -@import 'base/mixins'; - -## THEMING -## ------- -## Set up this file to import an edX theme library if the environment -## indicates that a theme should be used. The assumption is that the -## theme resides outside of this main edX repository, in a directory -## called themes//, with its base Sass file in -## themes//static/sass/_.scss. That one entry -## point can be used to @import in as many other things as needed. -% if env["FEATURES"].get("USE_CUSTOM_THEME", False): - // import theme's Sass overrides - @import '${env.get('THEME_NAME')}'; -% endif - -footer#footer-openedx { - @import 'base/reset'; - @import 'base/extends'; - @import 'base/base'; -} - -// base - elements -@import 'elements/typography'; - -// shared - platform -@import 'shared/footer'; diff --git a/lms/static/sass/lms-footer.scss b/lms/static/sass/lms-footer.scss new file mode 100644 index 000000000000..ba292cc8e901 --- /dev/null +++ b/lms/static/sass/lms-footer.scss @@ -0,0 +1,26 @@ +// Footer for OpenEdX (left-to-right) +// ================================== + +// libs and resets *do not edit* +@import 'bourbon/bourbon'; // lib - bourbon +@import 'vendor/bi-app/bi-app-ltr'; // set the layout for left to right languages + +// base - utilities +@import 'base/variables'; +@import 'base/mixins'; + +// This comment is used by preprocess_assets.py to include resources from a +// theme, for old-style deprecated theming. +// + +footer#footer-openedx { + @import 'base/reset'; + @import 'base/extends'; + @import 'base/base'; +} + +// base - elements +@import 'elements/typography'; + +// shared - platform +@import 'shared/footer'; diff --git a/lms/static/sass/lms-footer.scss.mako b/lms/static/sass/lms-footer.scss.mako deleted file mode 100644 index 0b4aff0381cf..000000000000 --- a/lms/static/sass/lms-footer.scss.mako +++ /dev/null @@ -1,35 +0,0 @@ -// Footer for OpenEdX (left-to-right) -// ================================== - -// libs and resets *do not edit* -@import 'bourbon/bourbon'; // lib - bourbon -@import 'vendor/bi-app/bi-app-ltr'; // set the layout for left to right languages - -// base - utilities -@import 'base/variables'; -@import 'base/mixins'; - -## THEMING -## ------- -## Set up this file to import an edX theme library if the environment -## indicates that a theme should be used. The assumption is that the -## theme resides outside of this main edX repository, in a directory -## called themes//, with its base Sass file in -## themes//static/sass/_.scss. That one entry -## point can be used to @import in as many other things as needed. -% if env["FEATURES"].get("USE_CUSTOM_THEME", False): - // import theme's Sass overrides - @import '${env.get('THEME_NAME')}'; -% endif - -footer#footer-openedx { - @import 'base/reset'; - @import 'base/extends'; - @import 'base/base'; -} - -// base - elements -@import 'elements/typography'; - -// shared - platform -@import 'shared/footer'; diff --git a/lms/static/sass/lms-main-rtl.scss b/lms/static/sass/lms-main-rtl.scss new file mode 100644 index 000000000000..7ab3e3cd35f7 --- /dev/null +++ b/lms/static/sass/lms-main-rtl.scss @@ -0,0 +1,21 @@ +// lms - css application architecture +// ==================== + +// libs and resets *do not edit* +@import 'bourbon/bourbon'; // lib - bourbon +@import 'vendor/bi-app/bi-app-rtl'; // set the layout for right to left languages +@import 'base/variables-rtl'; + +// BASE *default edX offerings* +// ==================== + +// base - utilities +@import 'base/reset'; +@import 'base/variables'; +@import 'base/mixins'; + +// This comment is used by preprocess_assets.py to include resources from a +// theme, for old-style deprecated theming. +// + +@import 'build-lms'; // shared app style assets/rendering diff --git a/lms/static/sass/lms-main-rtl.scss.mako b/lms/static/sass/lms-main-rtl.scss.mako deleted file mode 100644 index dcb06ff91a2f..000000000000 --- a/lms/static/sass/lms-main-rtl.scss.mako +++ /dev/null @@ -1,30 +0,0 @@ -// lms - css application architecture -// ==================== - -// libs and resets *do not edit* -@import 'bourbon/bourbon'; // lib - bourbon -@import 'vendor/bi-app/bi-app-rtl'; // set the layout for right to left languages -@import 'base/variables-rtl'; - -// BASE *default edX offerings* -// ==================== - -// base - utilities -@import 'base/reset'; -@import 'base/variables'; -@import 'base/mixins'; - -## THEMING -## ------- -## Set up this file to import an edX theme library if the environment -## indicates that a theme should be used. The assumption is that the -## theme resides outside of this main edX repository, in a directory -## called themes//, with its base Sass file in -## themes//static/sass/_.scss. That one entry -## point can be used to @import in as many other things as needed. -% if env["FEATURES"].get("USE_CUSTOM_THEME", False): - // import theme's Sass overrides - @import '${env.get('THEME_NAME')}'; -% endif - -@import 'build-lms'; // shared app style assets/rendering diff --git a/lms/static/sass/lms-main.scss b/lms/static/sass/lms-main.scss new file mode 100644 index 000000000000..1a79ca04426f --- /dev/null +++ b/lms/static/sass/lms-main.scss @@ -0,0 +1,20 @@ +// lms - css application architecture +// ==================== + +// libs and resets *do not edit* +@import 'bourbon/bourbon'; // lib - bourbon +@import 'vendor/bi-app/bi-app-ltr'; // set the layout for left to right languages + +// BASE *default edX offerings* +// ==================== + +// base - utilities +@import 'base/reset'; +@import 'base/variables'; +@import 'base/mixins'; + +// This comment is used by preprocess_assets.py to include resources from a +// theme, for old-style deprecated theming. +// + +@import 'build-lms'; // shared app style assets/rendering diff --git a/lms/static/sass/lms-main.scss.mako b/lms/static/sass/lms-main.scss.mako deleted file mode 100644 index 83d7be23d3f8..000000000000 --- a/lms/static/sass/lms-main.scss.mako +++ /dev/null @@ -1,30 +0,0 @@ -// lms - css application architecture -// ==================== - -// libs and resets *do not edit* -@import 'bourbon/bourbon'; // lib - bourbon -@import 'vendor/bi-app/bi-app-ltr'; // set the layout for left to right languages -@import 'base/variables-ltr'; - -// BASE *default edX offerings* -// ==================== - -// base - utilities -@import 'base/reset'; -@import 'base/variables'; -@import 'base/mixins'; - -## THEMING -## ------- -## Set up this file to import an edX theme library if the environment -## indicates that a theme should be used. The assumption is that the -## theme resides outside of this main edX repository, in a directory -## called themes//, with its base Sass file in -## themes//static/sass/_.scss. That one entry -## point can be used to @import in as many other things as needed. -% if env["FEATURES"].get("USE_CUSTOM_THEME", False): - // import theme's Sass overrides - @import '${env.get('THEME_NAME')}'; -% endif - -@import 'build-lms'; // shared app style assets/rendering diff --git a/lms/static/sass/multicourse/_course_about.scss b/lms/static/sass/multicourse/_course_about.scss index d3c2f7d37556..5027ccdc67c2 100644 --- a/lms/static/sass/multicourse/_course_about.scss +++ b/lms/static/sass/multicourse/_course_about.scss @@ -159,7 +159,7 @@ } #register_error { - background: $error-red; + background: $error-color; border: 1px solid rgb(202, 17, 17); color: rgb(143, 14, 14); display: none; @@ -405,7 +405,7 @@ .opencourseware { text-indent: -9999px; - background: url('../images/opencourseware.png') 0 0 no-repeat; + background: url('#{$static-path}/images/opencourseware.png') 0 0 no-repeat; width: 266px; height: 31px; margin-bottom: $baseline; @@ -419,7 +419,7 @@ li { list-style: none; padding-left: 29px; - background: url('../images/link-icon.png') left center no-repeat; + background: url('#{$static-path}/images/link-icon.png') left center no-repeat; } } } diff --git a/lms/static/sass/multicourse/_edge.scss b/lms/static/sass/multicourse/_edge.scss index 996825c7fd3c..1a04d367ef67 100644 --- a/lms/static/sass/multicourse/_edge.scss +++ b/lms/static/sass/multicourse/_edge.scss @@ -175,7 +175,7 @@ $paleYellow: #fffcf1; width: 263px; height: 72px; margin: 150px auto 50px; - background: url(../images/edx-theme/edx-edge-logo-large.png) no-repeat; + background: url('#{$static-path}/images/edx-theme/edx-edge-logo-large.png') no-repeat; text-indent: -9999px; overflow: hidden; } diff --git a/lms/static/sass/views/_teams.scss b/lms/static/sass/views/_teams.scss index 688535cf0f4d..66959895fad6 100644 --- a/lms/static/sass/views/_teams.scss +++ b/lms/static/sass/views/_teams.scss @@ -723,11 +723,11 @@ .u-field.error { input, textarea { - border-color: $danger-red; + border-color: $error-color; } .u-field-message-help, .u-field-description-message { - color: $danger-red !important; + color: $error-color !important; } } diff --git a/lms/static/sass/views/_verification.scss b/lms/static/sass/views/_verification.scss index 979c5cf95666..7057a4ce2e9b 100644 --- a/lms/static/sass/views/_verification.scss +++ b/lms/static/sass/views/_verification.scss @@ -1311,7 +1311,7 @@ display: block; width: 45px; height: 45px; - background: transparent url('../images/verified-ribbon.png') no-repeat 0 0; + background: transparent url('#{$static-path}/images/verified-ribbon.png') no-repeat 0 0; } .action-intro, .action-select { diff --git a/lms/static/themed_sass/README.rst b/lms/static/themed_sass/README.rst new file mode 100644 index 000000000000..1f2696c41e4b --- /dev/null +++ b/lms/static/themed_sass/README.rst @@ -0,0 +1,2 @@ +When USE_CUSTOM_THEME is true, .scss files are pre-processed to add imports of +the theme settings. This directory will hold the output of the pre-processing. diff --git a/lms/templates/courseware/course_about.html b/lms/templates/courseware/course_about.html index 870d4785ed4f..c8df28da92b5 100644 --- a/lms/templates/courseware/course_about.html +++ b/lms/templates/courseware/course_about.html @@ -17,7 +17,7 @@ ga=microsite.get_value('google_analytics_file', 'theme-google-analytics.html') ) else: - google_analytics_file = '../google_analytics.html' + google_analytics_file = '../google-analytics.html' %> <%include file="${google_analytics_file}" /> diff --git a/lms/templates/google_analytics.html b/lms/templates/google-analytics.html similarity index 100% rename from lms/templates/google_analytics.html rename to lms/templates/google-analytics.html diff --git a/lms/templates/header.html b/lms/templates/header.html new file mode 100644 index 000000000000..b3732c39128f --- /dev/null +++ b/lms/templates/header.html @@ -0,0 +1,19 @@ +<%namespace name='static' file='static_content.html'/> +<%! +from microsite_configuration import microsite +%> +<% +theme_enabled = settings.FEATURES.get("USE_CUSTOM_THEME", False) +is_microsite = microsite.is_request_in_microsite() +style_overrides_file = microsite.get_value('css_overrides_file') +%> + +% if style_overrides_file: + +% endif + +% if theme_enabled and not is_microsite: + <%include file="theme-header.html" /> +% else: + <%include file="${microsite.get_template_path('navigation.html')}" /> +% endif diff --git a/lms/templates/main.html b/lms/templates/main.html index 0f9839ace7f3..e95328a25b54 100644 --- a/lms/templates/main.html +++ b/lms/templates/main.html @@ -4,6 +4,7 @@ from django.core.urlresolvers import reverse from django.utils.http import urlquote_plus from django.utils.translation import ugettext as _ +from django.utils.translation import get_language_bidi from microsite_configuration import microsite from microsite_configuration import page_title_breadcrumbs from branding import api as branding_api @@ -62,7 +63,13 @@ <%static:css group='style-vendor'/> - <%static:css group='style-main'/> + ## route around the overwhelmingly complicated static:css nonsense + <% + application_css_path = "css/lms-main{rtl}.css".format( + rtl="-rtl" if get_language_bidi() else "", + ) + %> + % if disable_courseware_js: <%static:js group='base_vendor'/> @@ -85,30 +92,7 @@ <%block name="headextra"/> -<% - if theme_enabled() and not is_microsite(): - header_extra_file = 'theme-head-extra.html' - header_file = 'theme-header.html' - google_analytics_file = 'theme-google-analytics.html' - - style_overrides_file = None - - else: - header_extra_file = microsite.get_template_path('header_extra.html') - - if settings.FEATURES['IS_EDX_DOMAIN'] and not is_microsite(): - header_file = microsite.get_template_path('navigation-edx.html') - else: - header_file = microsite.get_template_path('navigation.html') - - google_analytics_file = microsite.get_template_path('google_analytics.html') - - style_overrides_file = microsite.get_value('css_overrides_file') -%> - - % if header_extra_file: - <%include file="${header_extra_file}" /> - % endif + <%static:optional_include_mako file="header-extra.html" with_microsite="True" /> <%include file="widgets/optimizely.html" /> <%include file="widgets/segment-io.html" /> @@ -116,11 +100,7 @@ - <%include file="${google_analytics_file}" /> - -% if style_overrides_file: - -% endif + <%static:optional_include_mako file="google-analytics.html" with_microsite="True" /> @@ -132,7 +112,7 @@ #content">${_("Skip to main content")} % if not disable_header: - <%include file="${header_file}" /> + <%include file="header.html" /> % endif
@@ -141,16 +121,7 @@
% if not disable_footer: - <%block name="footer"> - ## Can be overridden by child templates wanting to hide the footer. - % if theme_enabled() and not is_microsite(): - <%include file="theme-footer.html" /> - % elif settings.FEATURES.get('IS_EDX_DOMAIN', False) and not is_microsite(): - <%include file="footer-edx-v3.html" /> - % else: - <%include file="${microsite.get_template_path('footer.html')}" /> - % endif - + <%include file="themable-footer.html" /> % endif % if not disable_window_wrap: diff --git a/lms/templates/themable-footer.html b/lms/templates/themable-footer.html new file mode 100644 index 000000000000..dc688d9f4340 --- /dev/null +++ b/lms/templates/themable-footer.html @@ -0,0 +1,13 @@ +<%! +from microsite_configuration import microsite +%> +<% +theme_enabled = settings.FEATURES.get("USE_CUSTOM_THEME", False) +is_microsite = microsite.is_request_in_microsite() +%> + +% if theme_enabled and not is_microsite: + <%include file="theme-footer.html" /> +% else: + <%include file="${microsite.get_template_path('footer.html')}" /> +% endif diff --git a/openedx/core/djangoapps/theming/__init__.py b/openedx/core/djangoapps/theming/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/openedx/core/djangoapps/theming/core.py b/openedx/core/djangoapps/theming/core.py new file mode 100644 index 000000000000..4d114dc3ef99 --- /dev/null +++ b/openedx/core/djangoapps/theming/core.py @@ -0,0 +1,62 @@ +""" +Core logic for Comprehensive Theming. +""" + +from django.conf import settings + +import edxmako + + +def comprehensive_theme_changes(theme_dir): + """ + Calculate the set of changes needed to enable a comprehensive theme. + + Arguments: + theme_dir (path.path): the full path to the theming directory to use. + + Returns: + A dict indicating the changes to make: + + * 'settings': a dictionary of settings names and their new values. + + * 'mako_paths': a list of directories to prepend to the edxmako + template lookup path. + + """ + + changes = { + 'settings': {}, + 'mako_paths': [], + } + + templates_dir = theme_dir / "lms" / "templates" + if templates_dir.isdir(): + changes['settings']['TEMPLATE_DIRS'] = [templates_dir] + settings.TEMPLATE_DIRS + changes['mako_paths'].append(templates_dir) + + staticfiles_dir = theme_dir / "lms" / "static" + if staticfiles_dir.isdir(): + changes['settings']['STATICFILES_DIRS'] = [staticfiles_dir] + settings.STATICFILES_DIRS + + locale_dir = theme_dir / "lms" / "conf" / "locale" + if locale_dir.isdir(): + changes['settings']['LOCALE_PATHS'] = [locale_dir] + settings.LOCALE_PATHS + + favicon = theme_dir / "lms" / "static" / "images" / "favicon.ico" + if favicon.isfile(): + changes['settings']['FAVICON_PATH'] = str(favicon) + + return changes + + +def enable_comprehensive_theme(theme_dir): + """ + Add directories to relevant paths for comprehensive theming. + """ + changes = comprehensive_theme_changes(theme_dir) + + # Use the changes + for name, value in changes['settings'].iteritems(): + setattr(settings, name, value) + for template_dir in changes['mako_paths']: + edxmako.paths.add_lookup('main', template_dir, prepend=True) diff --git a/openedx/core/djangoapps/theming/startup.py b/openedx/core/djangoapps/theming/startup.py new file mode 100644 index 000000000000..ae217804b735 --- /dev/null +++ b/openedx/core/djangoapps/theming/startup.py @@ -0,0 +1,14 @@ +""" +Startup code for Comprehensive Theming +""" + +from path import Path as path +from django.conf import settings + +from .core import enable_comprehensive_theme + + +def run(): + """Enable comprehensive theming, if we should.""" + if settings.COMP_THEME_DIR: + enable_comprehensive_theme(theme_dir=path(settings.COMP_THEME_DIR)) diff --git a/openedx/core/djangoapps/theming/test_util.py b/openedx/core/djangoapps/theming/test_util.py new file mode 100644 index 000000000000..3a8dc011acb8 --- /dev/null +++ b/openedx/core/djangoapps/theming/test_util.py @@ -0,0 +1,89 @@ +""" +Test helpers for Comprehensive Theming. +""" + +from functools import wraps +import os +import os.path + +from mock import patch + +from django.conf import settings +from django.test.utils import override_settings + +import edxmako + +from .core import comprehensive_theme_changes + + +def with_comp_theme(theme_dir): + """ + A decorator to run a test with a particular comprehensive theme. + + Arguments: + theme_dir (str): the full path to the theme directory to use. + This will likely use `settings.REPO_ROOT` to get the full path. + + """ + # This decorator gets the settings changes needed for a theme, and applies + # them using the override_settings and edxmako.paths.add_lookup context + # managers. + + changes = comprehensive_theme_changes(theme_dir) + + def _decorator(func): # pylint: disable=missing-docstring + @wraps(func) + def _decorated(*args, **kwargs): # pylint: disable=missing-docstring + with override_settings(COMP_THEME_DIR=theme_dir, **changes['settings']): + with edxmako.save_lookups(): + for template_dir in changes['mako_paths']: + edxmako.paths.add_lookup('main', template_dir, prepend=True) + + return func(*args, **kwargs) + return _decorated + return _decorator + + +def with_is_edx_domain(is_edx_domain): + """ + A decorator to run a test as if IS_EDX_DOMAIN is true or false. + + We are transitioning away from IS_EDX_DOMAIN and are moving toward an edX + theme. This decorator changes both settings to let tests stay isolated + from the details. + + Arguments: + is_edx_domain (bool): are we an edX domain or not? + + """ + # This is weird, it's a decorator that conditionally applies other + # decorators, which is confusing. + def _decorator(func): # pylint: disable=missing-docstring + if is_edx_domain: + # This applies @with_comp_theme to the func. + func = with_comp_theme(settings.REPO_ROOT / "themes" / "edx.org")(func) + + # This applies @patch.dict() to the func to set IS_EDX_DOMAIN. + func = patch.dict('django.conf.settings.FEATURES', {"IS_EDX_DOMAIN": is_edx_domain})(func) + + return func + + return _decorator + + +def dump_theming_info(): + """Dump a bunch of theming information, for debugging.""" + for namespace, lookup in edxmako.LOOKUP.items(): + print "--- %s: %s" % (namespace, lookup.template_args['module_directory']) + for directory in lookup.directories: + print " %s" % (directory,) + + print "=" * 80 + for dirname, __, filenames in os.walk(settings.MAKO_MODULE_DIR): + print "%s ----------------" % (dir,) + for filename in sorted(filenames): + if filename.endswith(".pyc"): + continue + with open(os.path.join(dirname, filename)) as f: + content = len(f.read()) + print " %s: %d" % (filename, content) diff --git a/openedx/core/djangoapps/theming/tests/__init__.py b/openedx/core/djangoapps/theming/tests/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/pavelib/assets.py b/pavelib/assets.py index 3089cd786b2f..cabd6e515e7c 100644 --- a/pavelib/assets.py +++ b/pavelib/assets.py @@ -1,37 +1,64 @@ """ Asset compilation and collection. """ + from __future__ import print_function + import argparse +import glob +import traceback + from paver import tasks from paver.easy import sh, path, task, cmdopts, needs, consume_args, call_task, no_help from watchdog.observers import Observer from watchdog.events import PatternMatchingEventHandler -import glob -import traceback + from .utils.envs import Env from .utils.cmd import cmd, django_cmd # setup baseline paths COFFEE_DIRS = ['lms', 'cms', 'common'] -SASS_DIRS = { - "lms/static/sass": "lms/static/css", - "cms/static/sass": "cms/static/css", - "common/static/sass": "common/static/css", - "lms/static/certificates/sass": "lms/static/certificates/css", -} +# A list of directories. Each will be paired with a sibling /css directory. +SASS_DIRS = [ + path("lms/static/sass"), + path("lms/static/themed_sass"), + path("cms/static/sass"), + path("common/static/sass"), + path("lms/static/certificates/sass"), +] SASS_LOAD_PATHS = ['common/static', 'common/static/sass'] SASS_CACHE_PATH = '/tmp/sass-cache' -edxapp_env = Env() -if edxapp_env.feature_flags.get('USE_CUSTOM_THEME', False): - theme_name = edxapp_env.env_tokens.get('THEME_NAME', '') - parent_dir = path(edxapp_env.REPO_ROOT).abspath().parent - theme_root = parent_dir / "themes" / theme_name - COFFEE_DIRS.append(theme_root) - SASS_DIRS[theme_root / "static" / "sass"] = None +def configure_paths(): + """Configure our paths based on settings. Called immediately.""" + edxapp_env = Env() + if edxapp_env.feature_flags.get('USE_CUSTOM_THEME', False): + theme_name = edxapp_env.env_tokens.get('THEME_NAME', '') + parent_dir = path(edxapp_env.REPO_ROOT).abspath().parent + theme_root = parent_dir / "themes" / theme_name + COFFEE_DIRS.append(theme_root) + sass_dir = theme_root / "static" / "sass" + css_dir = theme_root / "static" / "css" + if sass_dir.isdir(): + css_dir.mkdir_p() + SASS_DIRS.append(sass_dir) + + if edxapp_env.env_tokens.get("COMP_THEME_DIR", ""): + theme_dir = path(edxapp_env.env_tokens["COMP_THEME_DIR"]) + lms_sass = theme_dir / "lms" / "static" / "sass" + lms_css = theme_dir / "lms" / "static" / "css" + if lms_sass.isdir(): + lms_css.mkdir_p() + SASS_DIRS.append(lms_sass) + studio_sass = theme_dir / "studio" / "static" / "sass" + studio_css = theme_dir / "studio" / "static" / "css" + if studio_sass.isdir(): + studio_css.mkdir_p() + SASS_DIRS.append(studio_sass) + +configure_paths() class CoffeeScriptWatcher(PatternMatchingEventHandler): @@ -71,7 +98,7 @@ def register(self, observer): """ register files with observer """ - for dirname in SASS_LOAD_PATHS + SASS_DIRS.keys(): + for dirname in SASS_LOAD_PATHS + SASS_DIRS: paths = [] if '*' in dirname: paths.extend(glob.glob(dirname)) @@ -137,7 +164,7 @@ def coffeescript_files(): """ return find command for paths containing coffee files """ - dirs = " ".join([Env.REPO_ROOT / coffee_dir for coffee_dir in COFFEE_DIRS]) + dirs = " ".join(Env.REPO_ROOT / coffee_dir for coffee_dir in COFFEE_DIRS) return cmd('find', dirs, '-type f', '-name \"*.coffee\"') @@ -176,10 +203,11 @@ def compile_sass(options): if options.get('force'): parts.append("--force") parts.append("--load-path .") - for load_path in SASS_LOAD_PATHS + SASS_DIRS.keys(): + for load_path in SASS_LOAD_PATHS + SASS_DIRS: parts.append("--load-path {path}".format(path=load_path)) - for sass_dir, css_dir in SASS_DIRS.items(): + for sass_dir in SASS_DIRS: + css_dir = sass_dir.parent / "css" if css_dir: parts.append("{sass}:{css}".format(sass=sass_dir, css=css_dir)) else: @@ -197,7 +225,13 @@ def compile_templated_sass(systems, settings): `settings` is the Django settings module to use. """ for sys in systems: - sh(django_cmd(sys, settings, 'preprocess_assets')) + if sys == "studio": + sys = "cms" + sh(django_cmd( + sys, settings, 'preprocess_assets', + '{sys}/static/sass/*.scss'.format(sys=sys), + '{sys}/static/themed_sass'.format(sys=sys) + )) print("\t\tFinished preprocessing {} assets.".format(sys)) diff --git a/pavelib/paver_tests/test_servers.py b/pavelib/paver_tests/test_servers.py index 3dbf20388eb9..95c1c0ef69b3 100644 --- a/pavelib/paver_tests/test_servers.py +++ b/pavelib/paver_tests/test_servers.py @@ -12,14 +12,23 @@ ) EXPECTED_SASS_COMMAND = ( "sass --update --cache-location /tmp/sass-cache --default-encoding utf-8 --style compressed" - " --quiet --load-path . --load-path common/static --load-path common/static/sass" - " --load-path lms/static/sass --load-path lms/static/certificates/sass" + " --quiet" + " --load-path ." + " --load-path common/static" + " --load-path common/static/sass" + " --load-path lms/static/sass" + " --load-path lms/static/themed_sass" " --load-path cms/static/sass --load-path common/static/sass" - " lms/static/sass:lms/static/css lms/static/certificates/sass:lms/static/certificates/css" - " cms/static/sass:cms/static/css common/static/sass:common/static/css" + " --load-path lms/static/certificates/sass" + " lms/static/sass:lms/static/css" + " lms/static/themed_sass:lms/static/css" + " cms/static/sass:cms/static/css" + " common/static/sass:common/static/css" + " lms/static/certificates/sass:lms/static/certificates/css" ) EXPECTED_PREPROCESS_ASSETS_COMMAND = ( "python manage.py {system} --settings={asset_settings} preprocess_assets" + " {system}/static/sass/*.scss {system}/static/themed_sass" ) EXPECTED_COLLECT_STATIC_COMMAND = ( "python manage.py {system} --settings={asset_settings} collectstatic --noinput > /dev/null" diff --git a/static/pattern-library/sass/utilities/_variables.scss b/static/pattern-library/sass/utilities/_variables.scss index ab31f9f0a72e..5b308d94f423 100644 --- a/static/pattern-library/sass/utilities/_variables.scss +++ b/static/pattern-library/sass/utilities/_variables.scss @@ -17,6 +17,8 @@ // ---------------------------- $em-base: 16; // deliberately sets bourbon-based em-base (http://bourbon.io/docs/#em-base) +$static-path: '..' !default; + // ---------------------------- // #GRID @@ -133,52 +135,52 @@ $palettes: ( // typography: config @include font-face( 'Open Sans', - '../../fonts/OpenSans/OpenSans-Light-webfont', + '#{$static-path}/../fonts/OpenSans/OpenSans-Light-webfont', 300, $file-formats: woff woff2 ttf ); @include font-face( 'Open Sans', - '../../fonts/OpenSans/OpenSans-LightItalic-webfont', + '#{$static-path}/../fonts/OpenSans/OpenSans-LightItalic-webfont', 300, italic, $file-formats: woff woff2 ttf ); @include font-face( 'Open Sans', - '../../fonts/OpenSans/OpenSans-Regular-webfont', + '#{$static-path}/../fonts/OpenSans/OpenSans-Regular-webfont', 400, $file-formats: woff woff2 ttf ); @include font-face( 'Open Sans', - '../../fonts/OpenSans/OpenSans-Italic-webfont', + '#{$static-path}/../fonts/OpenSans/OpenSans-Italic-webfont', 400, italic, $file-formats: woff woff2 ttf ); @include font-face( 'Open Sans', - '../../fonts/OpenSans/OpenSans-Semibold-webfont', + '#{$static-path}/../fonts/OpenSans/OpenSans-Semibold-webfont', 600, $file-formats: woff woff2 ttf ); @include font-face( 'Open Sans', - '../../fonts/OpenSans/OpenSans-SemiboldItalic-webfont', + '#{$static-path}/../fonts/OpenSans/OpenSans-SemiboldItalic-webfont', 600, italic, $file-formats: woff woff2 ttf ); @include font-face( 'Open Sans', - '../../fonts/OpenSans/OpenSans-Bold-webfont', + '#{$static-path}/../fonts/OpenSans/OpenSans-Bold-webfont', 700, $file-formats: woff woff2 ttf ); @include font-face( 'Open Sans', - '../../fonts/OpenSans/OpenSans-BoldItalic-webfont', + '#{$static-path}/../fonts/OpenSans/OpenSans-BoldItalic-webfont', 700, italic, $file-formats: woff woff2 ttf diff --git a/themes/README.rst b/themes/README.rst new file mode 100644 index 000000000000..547c7d01f1a0 --- /dev/null +++ b/themes/README.rst @@ -0,0 +1,178 @@ +##################### +Comprehensive Theming +##################### + + +Comprehensive Theming lets you customize the appearance of your Open edX +installation. You can override Sass and CSS settings, images, or entire HTML +templates. + +Eventually, Comprehensive Theming will obsolete existing theming mechanisms, +but for now they co-exist peacefully. This document describes how to use +Comprehensive Theming, and also the changes you'll need to make to keep other +theming mechanisms working. + + +Creating a theme +================ + +A theme is a directory of assets. You can create this directory wherever you +like, it does not have to be inside the edx-platform directory. The structure +within this directory mirrors the assets in the edx-platform repo itself. +Files you provide in your theme are used in place of the same-named files in +edx-platform. Here's a sample:: + + my-theme + └── lms + ├── static + │   ├── images + │   │   └── logo.png + │   └── sass + │   ├── _overrides.scss + │   ├── lms-main-rtl.scss + │   └── lms-main.scss + └── templates + ├── footer.html + └── header.html + +The top directory is named whatever you like. This example uses "my-theme". +The files provided here override the files in edx-platform. In this case, the +``my-theme/lms/static/sass/lms-main.scss`` file is used in place of the +``edx-platform/lms/static/sass/lms-main.scss`` file. + + +Images +------ + +Images can be substituted simply by placing the new image at the right place +in the theme directory. In our example above, the lms/static/images/logo.png +image is overridden. + + +Sass/CSS +-------- + +Most CSS styling in Open edX is done with Sass files compiled to CSS. You can +override individual settings by creating a new Sass file that uses the existing +file, and overrides the few settings you want. + +For example, to change the fonts used throughout the site, you can create an +``lms/static/sass/_overrides.scss`` file with the change you want:: + + $sans-serif: 'Helvetica'; + +The variables that can currently be overridden are defined in +``lms/static/sass/base/_variables.scss``. + +**Note:** We are currently in the middle of a re-engineering of the Sass +variables. They will change in the future. If you are interested, you can see +the new development in the `edX Pattern Library`_. + +.. _edX Pattern Library: http://ux.edx.org/ + +Then create ``lms/static/sass/lms-main.scss`` to use those overrides, and also +the rest of the definitions from the original file:: + + // Our overrides for settings we want to change. + @import 'overrides'; + + // Import the original styles from edx-platform. + @import 'lms/static/sass/lms-main'; + +Do this for each .scss file your site needs. + + +HTML Templates +-------------- + +You can make changes to HTML templates by copying them to your theme directory +in the appropriate place, and making the changes you need. Keep in mind that +in the future if you upgrade the Open edX code, you may have to update the +copied template in your theme also. + +Template Names +============== + +Here are the list of template names that you *should* use in your comprehensive +theme (so far): + +* ``header.html`` +* ``footer.html`` + +You should **not** use the following names in your comprehensive theme: + +* ``themable-footer.html`` + +If you look at the ``main.html`` template file, you will notice that it includes +``header.html`` and ``themable-footer.html``, rather than ``footer.html``. +You might be inclined to override ``themable-footer.html`` as a result. DO NOT +DO THIS. ``themable-footer.html`` is an additional layer of indirection that +is necessary to avoid breaking microsites, which also refers to a file named +``footer.html``. The goal is to eventually make comprehensive theming do +everything that microsites does now, and then deprecate and remove microsites +from the codebase. At that point, the ``themable-footer.html`` file will go +away, since the additional layer of indirection will no longer be necessary. + +Installing your theme +--------------------- + +To use your theme, you need to add a configuration value pointing to your theme +directory. There are two ways to do this. + +#. If you usually edit server-vars.yml: + + #. As the vagrant user, edit (or create) + /edx/app/edx_ansible/server-vars.yml to add the + ``edxapp_comp_theme_dir`` value:: + + edxapp_comp_theme_dir: '/full/path/to/my-theme' + + #. Run the update script:: + + $ sudo /edx/bin/update configuration master + $ sudo /edx/bin/update edx-platform HEAD + +#. Otherwise, edit the /edx/app/edxapp/lms.env.json file to add the + ``COMP_THEME_DIR`` value:: + + "COMP_THEME_DIR": "/full/path/to/my-theme", + +Restart your site. Your changes should now be visible. + + +"Stanford" theming +================== + +If you want to continue using the "Stanford" theming system, there are a few +changes you'll need to make. + +Create the following new files in the ``sass`` directory of your theme: + +* lms-main.scss +* lms-main-rtl.scss +* lms-course.scss +* lms-course-rtl.scss +* lms-footer.scss +* lms-footer-rtl.scss + +The contents of each of these files will be very similar. Here's what +``lms-main.scss`` should look like:: + + $static-path: '../../../..'; + @import 'lms/static/sass/lms-main'; + @import '_default'; + +Each file should set the ``$static-path`` variable to a relative path that +points to the ``lms/static`` directory inside of ``edx-platform``. Then, +it should ``@import`` the sass file under ``lms/static/sass`` that matches +its name: ``lms-footer.scss`` should import ``lms/static/sass/lms-footer``, +for example. Finally, the file should import the ``_default`` name, which +refers to the ``_default.scss`` Sass file that should already exist in your +Stanford theme directory. + +If your theme uses a different name than "default", you'll need to use that +name in the ``@import`` line. + +Run the ``update_assets`` command to recompile the theme:: + + $ paver update_assets lms --settings=aws diff --git a/lms/static/images/edx-theme/edx-logo-bw.png b/themes/edx.org/lms/static/images/logo-large.png similarity index 100% rename from lms/static/images/edx-theme/edx-logo-bw.png rename to themes/edx.org/lms/static/images/logo-large.png diff --git a/lms/static/images/edx-theme/edx-header-logo.png b/themes/edx.org/lms/static/images/logo.png similarity index 100% rename from lms/static/images/edx-theme/edx-header-logo.png rename to themes/edx.org/lms/static/images/logo.png diff --git a/lms/static/images/edx-theme/default-profile_120.png b/themes/edx.org/lms/static/images/profiles/default_120.png similarity index 100% rename from lms/static/images/edx-theme/default-profile_120.png rename to themes/edx.org/lms/static/images/profiles/default_120.png diff --git a/lms/static/images/edx-theme/default-profile_30.png b/themes/edx.org/lms/static/images/profiles/default_30.png similarity index 100% rename from lms/static/images/edx-theme/default-profile_30.png rename to themes/edx.org/lms/static/images/profiles/default_30.png diff --git a/lms/static/images/edx-theme/default-profile_50.png b/themes/edx.org/lms/static/images/profiles/default_50.png similarity index 100% rename from lms/static/images/edx-theme/default-profile_50.png rename to themes/edx.org/lms/static/images/profiles/default_50.png diff --git a/lms/static/images/edx-theme/default-profile_500.png b/themes/edx.org/lms/static/images/profiles/default_500.png similarity index 100% rename from lms/static/images/edx-theme/default-profile_500.png rename to themes/edx.org/lms/static/images/profiles/default_500.png diff --git a/themes/edx.org/lms/templates/footer.html b/themes/edx.org/lms/templates/footer.html new file mode 100644 index 000000000000..d74638c628c7 --- /dev/null +++ b/themes/edx.org/lms/templates/footer.html @@ -0,0 +1,81 @@ +## mako +<%! + from django.utils.translation import ugettext as _ + from branding.api import get_footer +%> +<% footer = get_footer(is_secure=is_secure) %> +<%namespace name='static' file='static_content.html'/> + +## WARNING: These files are specific to edx.org and are not used in installations outside of that domain. Open edX users will want to use the file "footer.html" for any changes or overrides. +
+ + +
+% if include_dependencies: + <%static:js group='base_vendor'/> + <%static:css group='style-vendor'/> + <%include file="widgets/segment-io.html" /> +% endif +% if footer_css_urls: + % for url in footer_css_urls: + + % endfor +% endif +% if footer_js_url: + +% endif + diff --git a/themes/edx.org/lms/templates/header.html b/themes/edx.org/lms/templates/header.html new file mode 100644 index 000000000000..3194120dc988 --- /dev/null +++ b/themes/edx.org/lms/templates/header.html @@ -0,0 +1,157 @@ +## mako +<%namespace name='static' file='static_content.html'/> +<%namespace file='main.html' import="login_query"/> +<%! +from django.core.urlresolvers import reverse +from django.utils.translation import ugettext as _ + +from microsite_configuration import microsite +from microsite_configuration.templatetags.microsite import platform_name + +# App that handles subdomain specific branding +import branding +# app that handles site status messages +from status.status import get_site_status_msg +%> + +## Provide a hook for themes to inject branding on top. +<%block name="navigation_top" /> + +<%block> +<% +try: + course_id = course.id.to_deprecated_string() +except: + # can't figure out a better way to get at a possibly-defined course var + course_id = None +site_status_msg = get_site_status_msg(course_id) +%> +% if site_status_msg: +
+
+ +

${site_status_msg}

+
+
+% endif + + + +% if course: + +% endif + +%if not user.is_authenticated(): + <%include file="forgot_password_modal.html" /> +%endif + +<%include file="help_modal.html"/> diff --git a/themes/red-theme/lms/static/css/README.txt b/themes/red-theme/lms/static/css/README.txt new file mode 100644 index 000000000000..5af45a252efd --- /dev/null +++ b/themes/red-theme/lms/static/css/README.txt @@ -0,0 +1,3 @@ +CSS files should go in this directory. If you are using a CSS preprocessor +like Sass, you should configure it to output CSS in this directory. Running +`paver compile_sass` should do the right thing in this case. diff --git a/themes/red-theme/lms/static/images/logo.png b/themes/red-theme/lms/static/images/logo.png new file mode 100644 index 000000000000..803bdfbaec43 Binary files /dev/null and b/themes/red-theme/lms/static/images/logo.png differ diff --git a/themes/red-theme/lms/static/sass/_overrides.scss b/themes/red-theme/lms/static/sass/_overrides.scss new file mode 100755 index 000000000000..4e5e1f2b6e31 --- /dev/null +++ b/themes/red-theme/lms/static/sass/_overrides.scss @@ -0,0 +1,7 @@ +// Theming overrides for sample theme +$header-bg: rgb(250,0,0); +$footer-bg: rgb(250,0,0); +$container-bg: rgb(250,0,0); +$content-wrapper-bg: rgb(250,0,0); +$serif: 'Comic Sans', 'Comic Sans MS'; +$sans-serif: 'Comic Sans', 'Comic Sans MS'; diff --git a/themes/red-theme/lms/static/sass/lms-main-rtl.scss b/themes/red-theme/lms/static/sass/lms-main-rtl.scss new file mode 100755 index 000000000000..3eaad226a2b3 --- /dev/null +++ b/themes/red-theme/lms/static/sass/lms-main-rtl.scss @@ -0,0 +1,5 @@ +// Theming overrides for sample theme +@import 'overrides'; + +// import the rest of the application +@import 'lms/static/sass/lms-main-rtl'; diff --git a/themes/red-theme/lms/static/sass/lms-main.scss b/themes/red-theme/lms/static/sass/lms-main.scss new file mode 100755 index 000000000000..d6287e821558 --- /dev/null +++ b/themes/red-theme/lms/static/sass/lms-main.scss @@ -0,0 +1,5 @@ +// Theming overrides for sample theme +@import 'overrides'; + +// import the rest of the application +@import 'lms/static/sass/lms-main'; diff --git a/themes/red-theme/lms/templates/footer.html b/themes/red-theme/lms/templates/footer.html new file mode 100755 index 000000000000..e87eb8f06feb --- /dev/null +++ b/themes/red-theme/lms/templates/footer.html @@ -0,0 +1,111 @@ +## mako +<%namespace name='static' file='static_content.html'/> +<%! +from django.core.urlresolvers import reverse +from django.utils.translation import ugettext as _ +from microsite_configuration.templatetags.microsite import platform_name +%> + + diff --git a/themes/red-theme/lms/templates/header.html b/themes/red-theme/lms/templates/header.html new file mode 100755 index 000000000000..d4b1caaada38 --- /dev/null +++ b/themes/red-theme/lms/templates/header.html @@ -0,0 +1,164 @@ +## mako +<%namespace name='static' file='static_content.html'/> +<%namespace file='main.html' import="login_query, stanford_theme_enabled"/> +<%! +from django.core.urlresolvers import reverse +from django.utils.translation import ugettext as _ + +# App that handles subdomain specific branding +import branding +# app that handles site status messages +from status.status import get_site_status_msg + +from microsite_configuration import microsite +from microsite_configuration.templatetags.microsite import platform_name +from ccx.overrides import get_current_ccx +%> + +## Provide a hook for themes to inject branding on top. +<%block name="navigation_top" /> + +<%block> +<% +try: + course_id = course.id.to_deprecated_string() +except: + # can't figure out a better way to get at a possibly-defined course var + course_id = None +site_status_msg = get_site_status_msg(course_id) +%> +% if site_status_msg: +
+
+ +

${site_status_msg}

+
+
+% endif + + + +% if course: + +% endif + +%if not user.is_authenticated(): + <%include file="forgot_password_modal.html" /> +%endif + +<%include file="help_modal.html"/>