impala details page stuff
|
@ -57,10 +57,34 @@ def performance_note(context, amount, listing=False):
|
|||
return new_context(**locals())
|
||||
|
||||
|
||||
@register.inclusion_tag('addons/impala/performance_note.html')
|
||||
@jinja2.contextfunction
|
||||
def impala_performance_note(context, amount, listing=False):
|
||||
return new_context(**locals())
|
||||
|
||||
|
||||
@register.inclusion_tag('addons/contribution.html')
|
||||
@jinja2.contextfunction
|
||||
def contribution(context, addon, text=None, src='', show_install=False,
|
||||
show_help=True):
|
||||
show_help=True, large=False):
|
||||
"""
|
||||
Show a contribution box.
|
||||
|
||||
Parameters:
|
||||
addon
|
||||
text: The begging text at the top of the box.
|
||||
src: The page where the contribution link is coming from.
|
||||
show_install: Whether or not to show the install button.
|
||||
show_help: Show "What's this?" link?
|
||||
"""
|
||||
has_suggested = bool(addon.suggested_amount)
|
||||
return new_context(**locals())
|
||||
|
||||
|
||||
@register.inclusion_tag('addons/impala/contribution.html')
|
||||
@jinja2.contextfunction
|
||||
def impala_contribution(context, addon, text=None, src='', show_install=False,
|
||||
show_help=True, large=False):
|
||||
"""
|
||||
Show a contribution box.
|
||||
|
||||
|
|
|
@ -346,7 +346,9 @@ class Addon(amo.models.OnChangeMixin, amo.models.ModelBase):
|
|||
|
||||
return urls
|
||||
|
||||
def get_url_path(self):
|
||||
def get_url_path(self, impala=False):
|
||||
if impala:
|
||||
return reverse('addons.i_detail', args=[self.slug])
|
||||
return reverse('addons.detail', args=[self.slug])
|
||||
|
||||
def meet_the_dev_url(self):
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
{% for addon in page %}
|
||||
<li>
|
||||
<div class="item">
|
||||
<a href="{{ addon.get_url_path() }}">
|
||||
<a href="{{ addon.get_url_path(impala=True) }}">
|
||||
<div class="icon">
|
||||
{% if first_page %}
|
||||
<img src="{{ addon.icon_url }}">
|
||||
|
|
|
@ -0,0 +1,176 @@
|
|||
{% if addon.charity %}
|
||||
{% set charity_url = addon.charity.outgoing_url %}
|
||||
{% set charity_name = addon.charity.name %}
|
||||
{% endif %}
|
||||
|
||||
<div class="notice c" id="contribution">
|
||||
<div class="aux{% if show_install %}-bottom{% endif %}">
|
||||
<div class="button-wrapper">
|
||||
<a class="button contribute prominent" id="contribute-button"
|
||||
href="{{ url('addons.contribute', addon.slug)|urlparams(src=src) }}">
|
||||
<b></b>{{ _('Contribute') }}
|
||||
</a>
|
||||
{% if show_install %}
|
||||
{# L10n: Click Contribute button OR Install button #}
|
||||
<span class="continue">{{ _('or') }}</span>
|
||||
{% set ver = version or None %}
|
||||
{{ install_button(addon, version=ver, show_contrib=False) }}
|
||||
{% endif %}
|
||||
|
||||
</div>{# /button-wrapper #}
|
||||
|
||||
<p class="suggestion">
|
||||
{% if has_suggested %}
|
||||
{% trans amt = addon.suggested_amount|currencyfmt('USD') %}
|
||||
<b>{{ amt }}</b> suggested
|
||||
{% endtrans %}
|
||||
{% endif %}
|
||||
</p>{# /suggestion #}
|
||||
</div>{# /aux #}
|
||||
|
||||
<h3>{{ _('Enjoy this add-on?') }}</h3>
|
||||
<p class="{% if show_install %}show-install{% endif %}">
|
||||
{% if text %}
|
||||
{{ text }}
|
||||
{% elif not addon.charity %}
|
||||
{{ _('The developer of this add-on asks that you help support its '
|
||||
'continued development by making a small contribution.') }}
|
||||
{% elif addon.charity_id == amo.FOUNDATION_ORG %}
|
||||
{% trans %}
|
||||
The developer of this add-on asks that you show your support
|
||||
by making a donation to the <a href="{{ charity_url }}">{{ charity_name }}</a>.
|
||||
{% endtrans %}
|
||||
{% else %}
|
||||
{% trans %}
|
||||
The developer of this add-on asks that you show your support
|
||||
by making a small contribution to <a href="{{ charity_url }}">{{ charity_name }}</a>.
|
||||
{% endtrans %}
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
<div id="contribute-box" class="jqmWindow">
|
||||
<form action="{{ url('addons.contribute', addon.slug) }}" method="get">
|
||||
<input type="hidden" name="source" value="{{ request.GET.get('src', src) }}"/>
|
||||
<h2>{{ _('Make a Contribution') }}</h2>
|
||||
<p class="support">
|
||||
{% with addon_name=addon.name, paypal_url='http://paypal.com' %}
|
||||
{% if not addon.charity %}
|
||||
{% trans %}
|
||||
Help support the continued development of
|
||||
<strong>{{ addon_name }}</strong> by making a small contribution
|
||||
through <a href="{{ paypal_url }}">Paypal</a>.
|
||||
{% endtrans %}
|
||||
{% elif addon.charity_id == amo.FOUNDATION_ORG %}
|
||||
{% trans %}
|
||||
To show your support for <b>{{ addon_name }}</b>, the developer asks
|
||||
that you make a donation to the <a href="{{ charity_url }}">{{ charity_name }}</a>
|
||||
through <a href="{{ paypal_url }}">Paypal</a>.
|
||||
{% endtrans %}
|
||||
{% else %}
|
||||
{% trans %}
|
||||
To show your support for <b>{{ addon_name }}</b>, the developer asks
|
||||
that you make a small contribution to <a href="{{ charity_url }}">{{ charity_name }}</a>
|
||||
through <a href="{{ paypal_url }}">Paypal</a>.
|
||||
{% endtrans %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
</p>
|
||||
|
||||
<h4>{{ _('How much would you like to contribute?') }}</h4>
|
||||
<div class="error" id="contrib-too-much"
|
||||
data-max-amount="{{ settings.MAX_CONTRIBUTION }}">
|
||||
{{ _('The maximum contribution amount is {0}.')|f(
|
||||
settings.MAX_CONTRIBUTION|currencyfmt('USD')) }}
|
||||
</div>
|
||||
<div class="error" id="contrib-too-little">
|
||||
{{ _('The minimum contribution amount is {0}.')|f(
|
||||
0.01|currencyfmt('USD')) }}
|
||||
</div>
|
||||
<div class="error" id="contrib-not-entered">
|
||||
{{ _('Contribution amount must be a number.') }}
|
||||
</div>
|
||||
<div class="error" id="paypal-error">
|
||||
{{ _('There was an error communicating with paypal. Please try again later.') }}
|
||||
</div>
|
||||
<ul>
|
||||
{% if has_suggested %}
|
||||
<li>
|
||||
<input type="radio" name="type" value="suggested"
|
||||
id="contrib-suggested" checked="checked"/>
|
||||
<label for="contrib-suggested">
|
||||
{# L10n: {1} is a currency amount (e.g., $5.00) #}
|
||||
{{ _('A one-time suggested contribution of {0}')|f(
|
||||
addon.suggested_amount|currencyfmt('USD')) }}
|
||||
</label>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li>
|
||||
<input type="radio" name="type" value="onetime"
|
||||
id="contrib-onetime"
|
||||
{% if not has_suggested %}checked="checked"{% endif %}/>
|
||||
<label>
|
||||
{# L10n: {0} is a currency symbol (e.g., $),
|
||||
{1} is an amount input field #}
|
||||
{{ _('A one-time contribution of {0} {1}')|f(
|
||||
'$', '<input type="text" name="onetime-amount" value=""/>')|safe }}
|
||||
</label>
|
||||
</li>
|
||||
{% if not settings.PAYPAL_USE_EMBEDDED %}
|
||||
<li>
|
||||
<input type="radio" name="type" value="monthly"
|
||||
id="contrib-monthly"/>
|
||||
<label for="contrib-monthly">
|
||||
{# L10n: {0} is a currency symbol (e.g., $),
|
||||
{1} is an amount input field #}
|
||||
{{ _('A regular monthly contribution of {0} {1}')|f(
|
||||
'$', '</label><input type="text" name="monthly-amount" value=""/>')|safe }}
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
|
||||
<h4 class="comment">
|
||||
<label for="contrib-comment">
|
||||
{{ _('Leave a comment or request with your contribution.') }}
|
||||
</label>
|
||||
</h4><span>{{ _('(optional)') }}</span>
|
||||
<textarea name="comment" id="contrib-comment"></textarea>
|
||||
<span class="commentlen"></span>
|
||||
|
||||
<button id="contribute-confirm" type="submit" class="prominent">
|
||||
{{ _('Make Contribution') }}
|
||||
</button>
|
||||
<span class="cancel"><a href="#">{{ _('No Thanks') }}</a></span>
|
||||
</form>
|
||||
</div>{# /contribute-box #}
|
||||
|
||||
|
||||
|
||||
</div>{# /notification #}
|
||||
|
||||
<div class="hidden">
|
||||
<div id="contribute-why" class="popup">
|
||||
<p class="msg">
|
||||
{% if addon.charity %}
|
||||
{% if addon.charity_id == amo.FOUNDATION_ORG %}
|
||||
{% trans %}
|
||||
The developer of this add-on would like you to consider making a
|
||||
donation to the <a href="{{ charity_url }}">{{ charity_name }}</a>
|
||||
if you enjoy using it.
|
||||
{% endtrans %}
|
||||
{% else %}
|
||||
{% trans %}
|
||||
The developer of this add-on would like you to consider making a
|
||||
small contribution to <a href="{{ charity_url }}">{{ charity_name }}</a>
|
||||
if you enjoy using it.
|
||||
{% endtrans %}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% trans %}
|
||||
Mozilla is committed to supporting a vibrant and healthy developer
|
||||
ecosystem. Your optional contribution helps sustain further development
|
||||
of this add-on.
|
||||
{% endtrans %}
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,210 @@
|
|||
{% extends "impala/base.html" %}
|
||||
|
||||
{% block title %}{{ page_title(addon.name) }}{% endblock %}
|
||||
{% block js %}{% include("amo/recaptcha_js.html") %}{% endblock %}
|
||||
{% block bodyclass %}gutter{% endblock %}
|
||||
|
||||
{% block extrahead %}
|
||||
{% if settings.ENGAGE_ROBOTS and addon.status == amo.STATUS_UNREVIEWED %}
|
||||
<meta name="robots" content="noindex">
|
||||
{% endif %}
|
||||
{% for preview in addon.all_previews %}
|
||||
<link rel="prefetch" href="{{ preview.image_url }}">
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{{ impala_breadcrumbs([(addon.type_url(), amo.ADDON_TYPES[addon.type]),
|
||||
(None, addon.name)]) }}
|
||||
|
||||
<aside class="secondary addon-vitals">
|
||||
{{ addon.average_rating|stars(large=True) }}
|
||||
<div><a href="#reviews">{{ _('{0} user reviews')|f(addon.total_reviews|numberfmt) }}</a></div>
|
||||
<div>{{ _('<b>{0}</b> active users')|f(addon.average_daily_users|numberfmt)|safe }}</div>
|
||||
<div class="widgets">
|
||||
{{ favorites_widget(addon) }}
|
||||
{% include 'addons/includes/collection_add_widget.html' %}
|
||||
{{ sharing_widget(addon) }}
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
{% set version = addon.current_version %}
|
||||
<section class="primary">
|
||||
<div id="addon" class="island c" role="main" data-id="{{ addon.id }}">
|
||||
<hgroup>
|
||||
<img src="{{ addon.get_icon_url(64) }}" class="icon">
|
||||
<h2 class="addon"{{ addon.name|locale_html }}>
|
||||
{{ addon.name }}
|
||||
<span class="version">{{ version.version }}</span>
|
||||
</h2>
|
||||
<h4 class="author">{{ _('by') }} {{ users_list(addon.listed_authors) }}</h4>
|
||||
</hgroup>
|
||||
<p{{ addon.summary|locale_html }}>{{ addon.summary|nl2br }}</p>
|
||||
{{ big_install_button(addon, show_warning=False) }}
|
||||
</div>
|
||||
|
||||
{% if settings.PERF_THRESHOLD and addon.ts_slowness >= settings.PERF_THRESHOLD %}
|
||||
{{ impala_performance_note(amount=addon.ts_slowness) }}
|
||||
{% endif %}
|
||||
|
||||
{% if addon.takes_contributions %}
|
||||
{{ impala_contribution(addon=addon, src='addon-detail') }}
|
||||
{% endif %}
|
||||
|
||||
</section>
|
||||
|
||||
{% if addon.type != amo.ADDON_PERSONA %}
|
||||
{% if addon.all_previews|length > 0 %}
|
||||
<section class="previews carousel">
|
||||
<a href="#" class="control prev">«</a>
|
||||
<a href="#" class="control next">»</a>
|
||||
<ul class="slider">
|
||||
{%- for preview in addon.all_previews -%}
|
||||
<li class="panel">
|
||||
<a class="screenshot thumbnail" rel="jquery-lightbox"
|
||||
href="{{ preview.image_url }}" title="{{ preview.caption }}">
|
||||
<img src="{{ preview.thumbnail_url }}">
|
||||
</a>
|
||||
</li>
|
||||
{%- endfor -%}
|
||||
</ul>
|
||||
</section>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if addon.description %}
|
||||
<section class="primary island">
|
||||
<h2>About this Add-on</h2>
|
||||
<p{{ addon.description|locale_html }}>{{ addon.description|nl2br }}</p>
|
||||
</section>
|
||||
{% endif %}
|
||||
|
||||
{# addon recommendations #}
|
||||
{% if recommendations %}
|
||||
<section class="primary island">
|
||||
<h2 class="compact-bottom">{{ _('Often used with…')|safe }}</h2>
|
||||
{{ recommendations|addon_grid }}
|
||||
</section>
|
||||
{% endif %}
|
||||
{# /recommendations #}
|
||||
|
||||
{% if author_addons %}
|
||||
<section class="primary island">
|
||||
<h2>
|
||||
{% trans count = addon.listed_authors|length,
|
||||
author = users_list(addon.listed_authors) %}
|
||||
Other add-ons by {{ author }}
|
||||
{% pluralize %}
|
||||
Other add-ons by these authors
|
||||
{% endtrans %}
|
||||
</h2>
|
||||
{{ author_addons|addon_grid }}
|
||||
</section>
|
||||
{% endif %}
|
||||
|
||||
<div class="secondary" role="navigation">
|
||||
|
||||
{% if addon.has_profile() and addon.listed_authors %}
|
||||
<div class="highlight">
|
||||
{% with single_dev = addon.listed_authors|random %}
|
||||
<h3 class="compact-bottom">
|
||||
{% trans count=addon.listed_authors|length %}
|
||||
Meet the Developer
|
||||
{% pluralize %}
|
||||
Meet the Developers
|
||||
{% endtrans %}
|
||||
</h3>
|
||||
<img class="avatar" alt="{{ single_dev.name }}" height="64"
|
||||
width="64" src="{{ single_dev.picture_url }}"/>
|
||||
<p>{{ _("Learn why {0} was created and find out what's next for this "
|
||||
'add-on.')|f(addon.name) }}</p>
|
||||
<p>
|
||||
<a class="more-info" href="{{ addon.meet_the_dev_url() }}">
|
||||
{% if addon.listed_authors|length > 1 %}
|
||||
{{ _('Meet the Developers') }}
|
||||
{% else %}
|
||||
{{ _('Meet {0}')|f(single_dev.name) }}
|
||||
{% endif %}
|
||||
</a>
|
||||
</p>
|
||||
{% endwith %}
|
||||
</div>
|
||||
{% endif %}{# /meet the devs #}
|
||||
|
||||
{# categories and other add-ons #}
|
||||
{% with categories = addon.categories.filter(application=APP.id) %}
|
||||
{% if categories or author_addons %}
|
||||
<div class="highlight">
|
||||
{% if categories %}
|
||||
<ul>
|
||||
{# TODO reverse URL #}
|
||||
{% for category in categories %}
|
||||
<li>
|
||||
<a href="{{ category.get_url_path() }}" class="more-info">
|
||||
{# L10n: {0} is the name of a category #}
|
||||
{{ _('See All {0} Add-ons')|f(category) }}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{# /categories #}
|
||||
|
||||
{# support box #}
|
||||
{% if addon.support_email or addon.support_url or addon.has_satisfaction %}
|
||||
<div id="support" class="highlight">
|
||||
<h3 class="compact-bottom">{{ _('Need help with this add-on?') }}</h3>
|
||||
<ul class="xoxo">
|
||||
{% if addon.has_satisfaction %}
|
||||
{# get satisfaction only supports en-US so no L10n here #}
|
||||
<li>Ask others on
|
||||
<a href="#" id="feedback_btn" class="feedback_btn"
|
||||
data-company="{{ addon.get_satisfaction_company }}"
|
||||
data-product="{{ addon.get_satisfaction_product }}"
|
||||
>Get Satisfaction</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if addon.support_email %}
|
||||
<li>{{ emaillink(addon.support_email.localized_string,
|
||||
_('E-mail your question')) }}</li>
|
||||
{% endif %}
|
||||
{% if addon.support_url %}
|
||||
<li><a href="{{ addon.support_url|external_url }}">{{
|
||||
_('Visit the support site') }}</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
|
||||
{% if addon.has_satisfaction %}
|
||||
<div id="get_satisfaction_container"></div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
{# /support #}
|
||||
|
||||
{{ tags_box(addon=addon, tags=tags) }}
|
||||
|
||||
{# related collections #}
|
||||
<div class="collections-add">
|
||||
<h3 class="compact-bottom">{{ _('Related Collections') }}</h3>
|
||||
|
||||
{% if not collections %}
|
||||
<p>{{ _('This add-on is not yet in any collections.') }}</p>
|
||||
{% else %}
|
||||
<ul class="addon-collections">
|
||||
{% for coll in collections %}
|
||||
<li><a href="{{ coll.get_url_path() }}"
|
||||
class="collectionitem">{{ coll.name }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
{# /collections #}
|
||||
|
||||
</div>{# /secondary #}
|
||||
|
||||
{% endblock content %}
|
|
@ -0,0 +1,30 @@
|
|||
{% if request.APP == amo.FIREFOX %}
|
||||
{% if listing %}
|
||||
<div class="performance-note">
|
||||
{{ _('This add-on can slow down Firefox.') }}
|
||||
<a href="#">{{ _('More…')|safe }}</a>
|
||||
<div class="popup warning hidden">
|
||||
<p class="msg">
|
||||
{% trans amount=amount|int %}
|
||||
<b>Performance warning:</b> Installing this add-on can slow down
|
||||
Firefox's start-up by <b>{{ amount }}%</b>.
|
||||
{% endtrans %}
|
||||
</p>
|
||||
<p>
|
||||
<a href="{{ url('perf.index' )}}">{{ _('Learn more…')|safe }}</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="notice performance-note">
|
||||
<h3>{{ _('This add-on can slow down Firefox.') }}</h3>
|
||||
<p>
|
||||
{% trans amount=amount|int %}
|
||||
Installing this add-on can slow down
|
||||
Firefox's start-up by <b>{{ amount }}%</b>.
|
||||
{% endtrans %}
|
||||
<a href="{{ url('perf.index' )}}">{{ _('Learn more…')|safe }}</a>
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
|
@ -46,6 +46,8 @@ urlpatterns = patterns('',
|
|||
|
||||
# URLs for a single add-on.
|
||||
('^addon/%s/' % ADDON_ID, include(detail_patterns)),
|
||||
# Impala deets.
|
||||
url('^i/addon/%s/$' % ADDON_ID, views.impala_addon_detail, name='addons.i_detail'),
|
||||
|
||||
# Accept extra junk at the end for a cache-busting build id.
|
||||
url('^addons/buttons.js(?:/.+)?$', 'addons.buttons.js'),
|
||||
|
|
|
@ -87,6 +87,33 @@ def addon_detail(request, addon):
|
|||
'addons.detail', args=[addon.slug]))
|
||||
|
||||
|
||||
@author_addon_clicked
|
||||
@addon_view
|
||||
def impala_addon_detail(request, addon):
|
||||
"""Add-ons details page dispatcher."""
|
||||
# addon needs to have a version and be valid for this app.
|
||||
if addon.type in request.APP.types:
|
||||
if addon.type == amo.ADDON_PERSONA:
|
||||
return persona_detail(request, addon)
|
||||
else:
|
||||
if not addon.current_version:
|
||||
raise http.Http404
|
||||
|
||||
return impala_extension_detail(request, addon)
|
||||
else:
|
||||
# Redirect to an app that supports this type.
|
||||
try:
|
||||
new_app = [a for a in amo.APP_USAGE if addon.type
|
||||
in a.types][0]
|
||||
except IndexError:
|
||||
raise http.Http404
|
||||
else:
|
||||
prefixer = urlresolvers.get_url_prefix()
|
||||
prefixer.app = new_app.short
|
||||
return http.HttpResponsePermanentRedirect(reverse(
|
||||
'addons.i_detail', args=[addon.slug]))
|
||||
|
||||
|
||||
def extension_detail(request, addon):
|
||||
"""Extensions details page."""
|
||||
|
||||
|
@ -140,6 +167,59 @@ def extension_detail(request, addon):
|
|||
return jingo.render(request, 'addons/details.html', data)
|
||||
|
||||
|
||||
def impala_extension_detail(request, addon):
|
||||
"""Extensions details page."""
|
||||
|
||||
# if current version is incompatible with this app, redirect
|
||||
comp_apps = addon.compatible_apps
|
||||
if comp_apps and request.APP not in comp_apps:
|
||||
prefixer = urlresolvers.get_url_prefix()
|
||||
prefixer.app = comp_apps.keys()[0].short
|
||||
return http.HttpResponsePermanentRedirect(reverse(
|
||||
'addons.detail', args=[addon.slug]))
|
||||
|
||||
# source tracking
|
||||
src = request.GET.get('src', 'addondetail')
|
||||
|
||||
# get satisfaction only supports en-US
|
||||
lang = translation.to_locale(translation.get_language())
|
||||
addon.has_satisfaction = (lang == 'en_US' and
|
||||
addon.get_satisfaction_company)
|
||||
|
||||
# other add-ons from the same author(s)
|
||||
author_addons = order_by_translation(addon.authors_other_addons, 'name')
|
||||
|
||||
# tags
|
||||
tags = addon.tags.not_blacklisted()
|
||||
|
||||
# addon recommendations
|
||||
recommended = MiniAddon.objects.valid().filter(
|
||||
recommended_for__addon=addon)[:5]
|
||||
|
||||
# popular collections this addon is part of
|
||||
collections = Collection.objects.listed().filter(
|
||||
addons=addon, application__id=request.APP.id)
|
||||
|
||||
data = {
|
||||
'addon': addon,
|
||||
'author_addons': author_addons,
|
||||
|
||||
'src': src,
|
||||
'tags': tags,
|
||||
|
||||
'recommendations': recommended,
|
||||
'review_form': ReviewForm(),
|
||||
'reviews': Review.objects.latest().filter(addon=addon),
|
||||
'get_replies': Review.get_replies,
|
||||
|
||||
'collections': collections.order_by('-subscribers')[:3],
|
||||
}
|
||||
if settings.REPORT_ABUSE:
|
||||
data['abuse_form'] = AbuseForm(request=request)
|
||||
|
||||
return jingo.render(request, 'addons/impala/details.html', data)
|
||||
|
||||
|
||||
@mobilized(extension_detail)
|
||||
def extension_detail(request, addon):
|
||||
return jingo.render(request, 'addons/mobile/details.html',
|
||||
|
|
|
@ -252,6 +252,32 @@ def breadcrumbs(context, items=list(), add_default=True, crumb_size=40):
|
|||
return jinja2.Markup(t)
|
||||
|
||||
|
||||
@register.function
|
||||
@jinja2.contextfunction
|
||||
def impala_breadcrumbs(context, items=list(), add_default=True, crumb_size=40):
|
||||
"""
|
||||
show a list of breadcrumbs. If url is None, it won't be a link.
|
||||
Accepts: [(url, label)]
|
||||
"""
|
||||
if add_default:
|
||||
app = context['request'].APP
|
||||
crumbs = [(urlresolvers.reverse('home'), page_name(app))]
|
||||
else:
|
||||
crumbs = []
|
||||
|
||||
# add user-defined breadcrumbs
|
||||
if items:
|
||||
try:
|
||||
crumbs += items
|
||||
except TypeError:
|
||||
crumbs.append(items)
|
||||
|
||||
crumbs = [(url, truncate(label, crumb_size)) for (url, label) in crumbs]
|
||||
c = {'breadcrumbs': crumbs}
|
||||
t = env.get_template('amo/impala/breadcrumbs.html').render(**c)
|
||||
return jinja2.Markup(t)
|
||||
|
||||
|
||||
@register.filter
|
||||
def json(s):
|
||||
return jsonlib.dumps(s)
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
{% if breadcrumbs %}
|
||||
<nav id="breadcrumbs">
|
||||
<ol>
|
||||
{% for target, label in breadcrumbs %}
|
||||
<li>
|
||||
{% if target %}
|
||||
<a href="{{ target }}">{{ label }}</a>
|
||||
{% else %}
|
||||
<span>{{ label }}</span>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ol>
|
||||
</nav>
|
||||
{% endif %}
|
|
@ -18,7 +18,7 @@
|
|||
</li>
|
||||
{% endmacro %}
|
||||
|
||||
<nav id="site-nav" class="c">
|
||||
<nav id="site-nav" class="menu-nav c">
|
||||
<ul>
|
||||
{{ section(_('Extensions'), url('browse.extensions'), extras, extensions) }}
|
||||
{{ section(_('Personas'), url('browse.personas'), extras, personas) }}
|
||||
|
|
|
@ -5,7 +5,7 @@ from tower import ugettext as _
|
|||
|
||||
|
||||
@jingo.register.filter
|
||||
def stars(num):
|
||||
def stars(num, large=False):
|
||||
# check for 0.0 incase None was cast to a float. Should
|
||||
# be safe since lowest rating you can give is 1.0
|
||||
if num is None or num == 0.0:
|
||||
|
@ -15,8 +15,9 @@ def stars(num):
|
|||
rating = '<span itemprop="rating">%s</span>' % num
|
||||
title = _('Rated %s out of 5 stars') % num
|
||||
msg = _('Rated %s out of 5 stars') % rating
|
||||
s = (u'<span class="stars stars-{num}" title="{title}">{msg}</span>'
|
||||
.format(num=num, title=title, msg=msg))
|
||||
size = 'large' if large else ''
|
||||
s = (u'<span class="stars {size} stars-{num}" title="{title}">{msg}</span>'
|
||||
.format(num=num, size=size, title=title, msg=msg))
|
||||
return jinja2.Markup(s) # Inspected by #10
|
||||
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
<div class="piechart"></div>
|
||||
<table data-report="apps" data-field="applications">
|
||||
</table>
|
||||
<a href="apps/">{{ _('See More Applications...') }}</a>
|
||||
<a href="apps/">{{ _('See more applications…') }}</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="toplist loading">
|
||||
|
@ -46,7 +46,7 @@
|
|||
<div class="piechart"></div>
|
||||
<table data-report="locales" data-field="locales">
|
||||
</table>
|
||||
<a href="locales/">{{ _('See More languages...') }}</a>
|
||||
<a href="locales/">{{ _('See more languages…') }}</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="toplist loading">
|
||||
|
@ -55,7 +55,7 @@
|
|||
<div class="piechart"></div>
|
||||
<table data-report="os" data-field="oses">
|
||||
</table>
|
||||
<a href="os/">{{ _('See more operating systems...') }}</a>
|
||||
<a href="os/">{{ _('See more operating systems…') }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
@import 'lib';
|
||||
|
||||
#addon {
|
||||
font-size: 1.2em;
|
||||
padding: 20px 20px 20px 104px;
|
||||
.icon {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
left: 20px;
|
||||
margin: 0 12px 1em 0;
|
||||
}
|
||||
h2 {
|
||||
font-size: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.version {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.notice {
|
||||
.border-radius(5px);
|
||||
padding: 1em 1em 1em 104px;
|
||||
background: #ECF5FE;
|
||||
margin-bottom: 1em;
|
||||
h3 {
|
||||
font-style: italic;
|
||||
font-size: 16px;
|
||||
}
|
||||
p {
|
||||
margin-top: .5em;
|
||||
}
|
||||
b {
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
.notice.performance-note {
|
||||
background: url("../../img/impala/turtle.png") no-repeat 28px 16px #FFF8DC;
|
||||
}
|
||||
|
||||
.addon-vitals {
|
||||
padding-top: 1em;
|
||||
font-size: 16px;
|
||||
line-height: 1.4em;
|
||||
div {
|
||||
margin-top: 4px;
|
||||
}
|
||||
.widgets {
|
||||
margin-top: 23px;
|
||||
font-size: 14px;
|
||||
.widget {
|
||||
color: #999;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.widget {
|
||||
padding-left: 21px;
|
||||
background: url(../../img/impala/widgets.png) no-repeat 0 4px;
|
||||
&:hover {
|
||||
color: @link;
|
||||
}
|
||||
&.favorite {
|
||||
&.faved {
|
||||
.sprite-pos(2, 20, 4px);
|
||||
}
|
||||
&:hover {
|
||||
.sprite-pos(1, 20, 4px);
|
||||
}
|
||||
}
|
||||
&.collection-add {
|
||||
.sprite-pos(3, 20, 4px);
|
||||
&:hover {
|
||||
.sprite-pos(4, 20, 4px);
|
||||
}
|
||||
}
|
||||
&.share {
|
||||
.sprite-pos(5, 20, 4px);
|
||||
&:hover {
|
||||
.sprite-pos(6, 20, 4px);
|
||||
}
|
||||
}
|
||||
&.ajax-loading {
|
||||
background: url(../../img/zamboni/loading-white.gif) no-repeat 0 2px !important;
|
||||
}
|
||||
}
|
||||
|
||||
#contribution {
|
||||
.aux {
|
||||
float: right;
|
||||
text-align: center;
|
||||
margin: 0 1em;
|
||||
p {
|
||||
font-size: 11px;
|
||||
}
|
||||
}
|
||||
#contribute-box {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.previews {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
margin: 2em 0;
|
||||
padding: 0 5%;
|
||||
.panel {
|
||||
width: 100% / 3;
|
||||
a {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
.control {
|
||||
font-size:
|
||||
display: block;
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 5%;
|
||||
text-decoration: none;
|
||||
font-size: 48px;
|
||||
font-family: @serif-stack;
|
||||
text-align: center;
|
||||
line-height: 140px;
|
||||
background: rgba(255,255,255,.5);
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
&.next {
|
||||
right: 0;
|
||||
}
|
||||
&.prev {
|
||||
left: 0;
|
||||
}
|
||||
&.disabled {
|
||||
color: #ccc;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
@import 'lib';
|
||||
|
||||
.button {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
font-size: 13px;
|
||||
padding: 5px 10px 7px;
|
||||
font-family: @head-sans;
|
||||
font-weight: bold;
|
||||
line-height: 1;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
color: #fff;
|
||||
.gradient-two-color(#669BE1, #5784BF);
|
||||
text-shadow: 0 1px 0 rgba(0,0,0,.5);
|
||||
.border-radius(6px);
|
||||
.box-shadow(0 1px rgba(0, 0, 0, 0.1), 0 -2px rgba(0, 0, 0, 0.1) inset);
|
||||
&.prominent {
|
||||
padding: 8px 16px 12px;
|
||||
font-size: 16px;
|
||||
.box-shadow(0 3px rgba(0, 0, 0, 0.1), 0 -4px rgba(0, 0, 0, 0.1) inset);
|
||||
}
|
||||
&.add {
|
||||
.gradient-two-color(#84C63C, #489615);
|
||||
color: #fff;
|
||||
span {
|
||||
padding-left: 16px;
|
||||
background: url(../../img/impala/button-icons.png) no-repeat 0 3px;
|
||||
}
|
||||
&.prominent {
|
||||
span {
|
||||
padding-left: 24px;
|
||||
.sprite-pos(3, 64, 3px);
|
||||
}
|
||||
&.disabled span {
|
||||
.sprite-pos(4, 64, 3px);
|
||||
}
|
||||
&.warning span {
|
||||
.sprite-pos(5, 64, 3px);
|
||||
}
|
||||
}
|
||||
&.warning {
|
||||
background: url(../../img/impala/warning-bg.png);
|
||||
color: #333;
|
||||
text-shadow: 0 -1px 0 rgba(255,255,255,.5);
|
||||
top: 0;
|
||||
span {
|
||||
.sprite-pos(2, 64, 3px);
|
||||
}
|
||||
}
|
||||
&.disabled {
|
||||
.gradient-two-color(#d1d4d7, #c1c5ca);
|
||||
color: #919497;
|
||||
.box-shadow(0 3px rgba(0, 0, 0, 0.05), 0 -4px rgba(0, 0, 0, 0.05) inset);
|
||||
text-shadow: 0 1px 0 rgba(255,255,255,.5);
|
||||
top: 0;
|
||||
span {
|
||||
.sprite-pos(1, 64, 3px);
|
||||
}
|
||||
}
|
||||
}
|
||||
&.contribute {
|
||||
&.prominent b {
|
||||
background: url(../../img/impala/button-icons.png) no-repeat;
|
||||
padding-left: 24px;
|
||||
margin-left: -4px;
|
||||
.sprite-pos(7, 64, 3px);
|
||||
}
|
||||
}
|
||||
&.developer {
|
||||
background: -moz-linear-gradient(#f84b4e, #bc2b1a);
|
||||
color: #fff;
|
||||
span {
|
||||
margin-left: -4px;
|
||||
padding-left: 24px;
|
||||
.sprite-pos(6, 64, 3px);
|
||||
}
|
||||
}
|
||||
}
|
||||
.button:hover,
|
||||
.button:focus,
|
||||
.button:active,
|
||||
.button.selected {
|
||||
text-decoration: none;
|
||||
.box-shadow(0 3px rgba(0, 0, 0, 0.1), 0 -4px rgba(0, 0, 0, 0.1) inset, 0 0 100px rgba(255, 255, 255, 0.2) inset);
|
||||
}
|
||||
|
||||
.button:active,
|
||||
.button.selected {
|
||||
top: 2px;
|
||||
.box-shadow(0 1px rgba(0, 0, 0, 0.1), 0 -4px rgba(0, 0, 0, 0.1) inset, 0 0 100px rgba(255, 255, 255, 0.2) inset);
|
||||
}
|
||||
|
||||
.button.small:hover,
|
||||
.button.small:focus,
|
||||
.button.small:active,
|
||||
.button.small.selected {
|
||||
.box-shadow(0 1px rgba(0, 0, 0, 0.1), 0 -2px rgba(0, 0, 0, 0.1) inset, 0 0 100px rgba(255, 255, 255, 0.2) inset);
|
||||
}
|
||||
|
||||
.button.small:active,
|
||||
.button.small.selected {
|
||||
top: 2px;
|
||||
.box-shadow(0 0px rgba(0, 0, 0, 0.1), 0 -2px rgba(0, 0, 0, 0.1) inset, 0 0 100px rgba(255, 255, 255, 0.2) inset);
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
@import 'lib';
|
||||
|
||||
.pager {
|
||||
font-family: @head-serif;
|
||||
font-family: @serif-stack;
|
||||
display: block;
|
||||
.prev, .next {
|
||||
height: 20px;
|
||||
|
@ -50,4 +50,27 @@
|
|||
}
|
||||
.html-rtl .island .pager {
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
|
||||
.slider {
|
||||
white-space: nowrap;
|
||||
position: relative;
|
||||
left: 0;
|
||||
-moz-transition-duration: .3s;
|
||||
-moz-transition-property: left, right;
|
||||
-webkit-transition-duration: .3s;
|
||||
-webkit-transition-property: left, right;
|
||||
}
|
||||
|
||||
.slider.noslide {
|
||||
-moz-transition: none;
|
||||
-webkit-transition: none;
|
||||
}
|
||||
|
||||
.slider > li {
|
||||
width: 100%;
|
||||
white-space: normal;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
top: 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
.sunbird,
|
||||
.seamonkey,
|
||||
.thunderbird,
|
||||
.editor-tools,
|
||||
.developer-hub {
|
||||
#footer {
|
||||
#footer-logo {
|
||||
display: none;
|
||||
}
|
||||
#copyright {
|
||||
clear: none;
|
||||
padding-top: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#footer {
|
||||
background: #33559b url(../../img/zamboni/global/bg-footer.png) 0 0 repeat-x;
|
||||
padding: 123px 0 5px 0;
|
||||
.section {
|
||||
max-width: 960px;
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
}
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
#footer-logo a,
|
||||
#footer-logo a:link,
|
||||
#footer-logo a:visited {
|
||||
background: url(../../img/zamboni/global/header-logos.png) 15px 0 no-repeat;
|
||||
}
|
||||
|
||||
#footer-logo a:hover,
|
||||
#footer-logo a:active {
|
||||
background: -moz-radial-gradient(center 45deg, ellipse closest-side, rgba(255,255,255,0.3) 0%, rgba(255,255,255,0) 100%),
|
||||
url(../../img/zamboni/global/header-logos.png) 15px 0 no-repeat;
|
||||
}
|
||||
|
||||
#footer-contents[dir="rtl"] {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#copyright {
|
||||
margin-left: 17px;
|
||||
}
|
||||
|
||||
.footerlogo {
|
||||
position: absolute;
|
||||
right: 25px;
|
||||
top: -64px;
|
||||
}
|
||||
|
||||
.html-rtl .footerlogo {
|
||||
right: auto;
|
||||
left: 25px;
|
||||
}
|
||||
|
||||
.developer-hub .footerlogo {
|
||||
right: -10px;
|
||||
top: -70px;
|
||||
}
|
||||
|
||||
.html-rtl.developer-hub .footerlogo {
|
||||
right: auto;
|
||||
left: -10px;
|
||||
}
|
||||
|
||||
#footer .section {
|
||||
min-height: 0;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
#footer-content {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
#footer-logo {
|
||||
margin-left: 3px;
|
||||
width: 10%;
|
||||
}
|
||||
#footer-menu {
|
||||
display: table;
|
||||
width: 70%;
|
||||
ul {
|
||||
display: table-row;
|
||||
}
|
||||
li {
|
||||
display: table-cell;
|
||||
width: 10%;
|
||||
padding: 11px 16px 0 0;
|
||||
float: none;
|
||||
}
|
||||
}
|
||||
|
||||
.footer-devhub-link {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
#social-footer {
|
||||
height: 68px;
|
||||
margin-bottom: 4px;
|
||||
display: table;
|
||||
font-size: 18px;
|
||||
font-style: italic;
|
||||
width: 80%;
|
||||
color: white;
|
||||
a:after {
|
||||
content: ' \00bb';
|
||||
}
|
||||
a:link,
|
||||
a:visited {
|
||||
color: white;
|
||||
}
|
||||
ul {
|
||||
display: table-row;
|
||||
li {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
&:first-child {
|
||||
line-height: 1.2em;
|
||||
font-size: 17px;
|
||||
width: 128px;
|
||||
}
|
||||
b {
|
||||
display: block;
|
||||
font-family: MetaBlack;
|
||||
font-style: normal;
|
||||
font-size: 22px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -11,11 +11,10 @@
|
|||
.gradient-two-color(#FCFDFE, #F4F8FC);
|
||||
border: 1px solid #C9DDF2;
|
||||
.border-radius(5px);
|
||||
.box-shadow(0 -2px 0 rgba(204, 223, 243, 0.3) inset, 0 0 2px rgba(0, 0, 0, 0.1));
|
||||
.box-shadow(0 -2px 0 rgba(204, 223, 243, 0.3) inset, 0 0 1px rgba(0, 0, 0, 0.1));
|
||||
display: block;
|
||||
margin-bottom: 15px;
|
||||
padding: 14px 14px 16px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
#masthead {
|
||||
|
@ -30,14 +29,7 @@
|
|||
float: left;
|
||||
}
|
||||
|
||||
#aux-nav .context,
|
||||
#aux-nav ul {
|
||||
background: -moz-linear-gradient(#9FA7AF, fadeout(#9FA7AF, 100%)) no-repeat left top;
|
||||
background-size: 1px 100%;
|
||||
display: inline-block;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
padding: 0 1em;
|
||||
#aux-nav {
|
||||
}
|
||||
|
||||
.site-title img {
|
||||
|
@ -59,7 +51,7 @@
|
|||
|
||||
/** site navigation */
|
||||
|
||||
#site-nav {
|
||||
.menu-nav {
|
||||
font-size: 12px;
|
||||
margin-left: 64px;
|
||||
z-index: 50;
|
||||
|
@ -68,15 +60,10 @@
|
|||
> li {
|
||||
float: left;
|
||||
position: relative;
|
||||
border-left: 1px solid #9FA7AF;
|
||||
left: -9px;
|
||||
> a {
|
||||
position: relative;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
z-index: 60;
|
||||
padding: 4px 8px;
|
||||
line-height: 12px;
|
||||
border-style: solid;
|
||||
.border-radius(3px 3px 0 0);
|
||||
border-color: transparent;
|
||||
|
@ -93,7 +80,7 @@
|
|||
}
|
||||
&:after {
|
||||
content: "";
|
||||
width: 100px;
|
||||
width: 160px;
|
||||
z-index: 62;
|
||||
height: 5px;
|
||||
background: #fff;
|
||||
|
@ -102,9 +89,6 @@
|
|||
left: 1px;
|
||||
}
|
||||
}
|
||||
&:first-child {
|
||||
border: 0;
|
||||
}
|
||||
> ul {
|
||||
width: 190px;
|
||||
position: absolute;
|
||||
|
@ -147,7 +131,7 @@
|
|||
}
|
||||
|
||||
.html-rtl {
|
||||
#site-nav > ul > li {
|
||||
.menu-nav > ul > li {
|
||||
border-left: 0;
|
||||
border-right: 1px solid #9FA7AF;
|
||||
float: right;
|
||||
|
@ -161,11 +145,59 @@
|
|||
}
|
||||
}
|
||||
|
||||
#site-nav {
|
||||
> ul {
|
||||
> li {
|
||||
border-left: 1px solid #9FA7AF;
|
||||
left: -9px;
|
||||
&:first-child {
|
||||
border: 0;
|
||||
}
|
||||
> a {
|
||||
padding: 4px 8px;
|
||||
line-height: 12px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#aux-nav {
|
||||
> ul {
|
||||
> li:not(:first-child):before {
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -1px;
|
||||
width: 1px;
|
||||
height: 32px;
|
||||
background: -moz-linear-gradient(#9FA7AF, fadeout(#9FA7AF, 100%)) no-repeat left top;
|
||||
background-size: 1px 100%;
|
||||
}
|
||||
> li {
|
||||
margin-left: 1px;
|
||||
> a {
|
||||
display: block;
|
||||
line-height: 32px;
|
||||
height: 32px;
|
||||
padding: 0 1em;
|
||||
.border-radius(0);
|
||||
}
|
||||
&:after {
|
||||
top: 32px;
|
||||
}
|
||||
> ul {
|
||||
top: 31px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/** search box */
|
||||
|
||||
.header-search {
|
||||
position: absolute;
|
||||
top: 64px;
|
||||
top: 63px;
|
||||
right: 0;
|
||||
background: #F8FBFF;
|
||||
border: 1px solid #98B2C9;
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
position: relative;
|
||||
margin: 5px 5px 5px 61px;
|
||||
border: 1px solid transparent;
|
||||
float: left;
|
||||
z-index: 20;
|
||||
h3 {
|
||||
color: #447BC4;
|
||||
|
@ -40,9 +39,11 @@
|
|||
}
|
||||
a {
|
||||
display: block;
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
}
|
||||
.button {
|
||||
display: inline-block;
|
||||
}
|
||||
.summary {
|
||||
height: 48px;
|
||||
width: 182px;
|
||||
|
@ -75,6 +76,7 @@
|
|||
z-index: 1;
|
||||
}
|
||||
&:hover {
|
||||
float: left;
|
||||
z-index: 25;
|
||||
background: #fff;
|
||||
border-color: #888;
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
@note-gray: #999;
|
||||
|
||||
// Font Stacks
|
||||
@copy-stack: "helvetica neue", arial, helvetica, sans-serif;
|
||||
@sans-stack: "helvetica neue", arial, helvetica, sans-serif;
|
||||
@head-sans: "trebuchet ms", sans-serif;
|
||||
@head-serif: Georgia, serif;
|
||||
@serif-stack: Georgia, serif;
|
||||
@mono-stack: "andale mono", monospace;
|
||||
|
||||
// Mixins
|
||||
|
@ -45,4 +45,12 @@
|
|||
background-image: linear-gradient(@color1, @color2);
|
||||
background-image: -moz-linear-gradient(@color1, @color2);
|
||||
background-image: -webkit-linear-gradient(@color1, @color2);
|
||||
}
|
||||
|
||||
.sprite(@url, @pos, @spacing, @offset) {
|
||||
background: url(@url) no-repeat;
|
||||
background-position: 0 (@spacing * @pos * -1 + @offset) + 0px;
|
||||
}
|
||||
.sprite-pos(@pos, @spacing, @offset) {
|
||||
background-position: 0 (@spacing * @pos * -1 + @offset) + 0px;
|
||||
}
|
|
@ -6,13 +6,24 @@
|
|||
width: 63px;
|
||||
height: 12px;
|
||||
background: url(../../img/impala/stars.png) no-repeat left top;
|
||||
text-indent: -9999px;
|
||||
margin-right: 4px;
|
||||
&.stars-4 { background-position: -13px 0; }
|
||||
&.stars-3 { background-position: -26px 0; }
|
||||
&.stars-2 { background-position: -39px 0; }
|
||||
&.stars-1 { background-position: -52px 0; }
|
||||
text-indent: -9999px;
|
||||
margin-right: 4px;
|
||||
&.large {
|
||||
display: block;
|
||||
background: url(../../img/impala/stars-16.png) no-repeat left top;
|
||||
width: 89px;
|
||||
height: 16px;
|
||||
&.stars-4 { background-position: -18px 0; }
|
||||
&.stars-3 { background-position: -36px 0; }
|
||||
&.stars-2 { background-position: -54px 0; }
|
||||
&.stars-1 { background-position: -70px 0; }
|
||||
}
|
||||
}
|
||||
|
||||
.html-rtl .stars {
|
||||
text-indent: 9999px;
|
||||
margin-right: 0;
|
||||
|
|
|
@ -24,32 +24,32 @@ a {
|
|||
}
|
||||
|
||||
.primary {
|
||||
margin-left: 210px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.primary, .html-rtl.gutter .primary {
|
||||
margin-left: 210px;
|
||||
.primary {
|
||||
margin-right: 210px;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.secondary {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
.secondary {
|
||||
width: 180px;
|
||||
.secondary, .html-rtl.gutter .primary {
|
||||
float: left;
|
||||
width: 180px;
|
||||
}
|
||||
|
||||
.html-rtl {
|
||||
.html-rtl, .gutter {
|
||||
.primary {
|
||||
margin-left: 0;
|
||||
margin-right: 210px;
|
||||
|
||||
.primary {
|
||||
margin-right: 0;
|
||||
margin-left: 210px;
|
||||
}
|
||||
|
||||
.secondary {
|
||||
float: left;
|
||||
}
|
||||
|
@ -59,6 +59,7 @@ a {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
.secondary {
|
||||
ul, ol {
|
||||
margin-bottom: 28px;
|
||||
|
@ -85,6 +86,23 @@ a {
|
|||
}
|
||||
}
|
||||
|
||||
#breadcrumbs {
|
||||
margin-bottom: 1.2em;
|
||||
font-family: @serif-stack;
|
||||
color: #666;
|
||||
li {
|
||||
display: inline;
|
||||
&:before {
|
||||
content: '\00bb';
|
||||
font-size: 1.3em;
|
||||
font-weight: bold;
|
||||
}
|
||||
&:first-child:before {
|
||||
content: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#promos {
|
||||
height: 270px;
|
||||
max-height: 270px;
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
|
||||
body {
|
||||
font-family: @copy-stack;
|
||||
font-family: @sans-stack;
|
||||
font-style: normal;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
@ -25,20 +25,42 @@ h1 {
|
|||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
pre, code, kbd, tt, samp, tt {
|
||||
font-family: @mono-stack;
|
||||
}
|
||||
|
||||
.primary {
|
||||
h2 {
|
||||
color: #333;
|
||||
font-family: @serif-stack;
|
||||
font-style: italic;
|
||||
}
|
||||
p {
|
||||
font-size: 14px;
|
||||
margin-top: 1em;
|
||||
color: #666;
|
||||
line-height: 1.3em;
|
||||
}
|
||||
}
|
||||
|
||||
.gutter {
|
||||
.primary, .secondary {
|
||||
font-family: @serif-stack;
|
||||
}
|
||||
}
|
||||
|
||||
.island h2 {
|
||||
color: #333;
|
||||
font-family: @head-serif;
|
||||
font-size: 18px;
|
||||
font-style: italic;
|
||||
margin-bottom: .5em;
|
||||
}
|
||||
|
||||
.secondary h2 {
|
||||
font-family: @copy-stack;
|
||||
font-family: @sans-stack;
|
||||
font-style: normal;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
color: #484848;
|
||||
|
|
После Ширина: | Высота: | Размер: 275 B |
После Ширина: | Высота: | Размер: 265 B |
После Ширина: | Высота: | Размер: 276 B |
После Ширина: | Высота: | Размер: 261 B |
После Ширина: | Высота: | Размер: 257 B |
После Ширина: | Высота: | Размер: 249 B |
После Ширина: | Высота: | Размер: 266 B |
После Ширина: | Высота: | Размер: 560 B |
После Ширина: | Высота: | Размер: 1.1 KiB |
После Ширина: | Высота: | Размер: 1.2 KiB |
После Ширина: | Высота: | Размер: 244 B |
После Ширина: | Высота: | Размер: 485 B |
После Ширина: | Высота: | Размер: 627 B |
После Ширина: | Высота: | Размер: 336 B |
После Ширина: | Высота: | Размер: 1.6 KiB |
После Ширина: | Высота: | Размер: 890 B |
После Ширина: | Высота: | Размер: 199 B |
После Ширина: | Высота: | Размер: 1.2 KiB |
|
@ -0,0 +1,7 @@
|
|||
$(function () {
|
||||
$(".previews").zCarousel({
|
||||
btnNext: ".previews .next",
|
||||
btnPrev: ".previews .prev",
|
||||
itemsPerPage: 3
|
||||
});
|
||||
});
|
|
@ -0,0 +1,81 @@
|
|||
/**
|
||||
* zCarousel: like jCarouselLite, but good.
|
||||
* by potch
|
||||
*
|
||||
* handles fluid layouts like a champ!
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
|
||||
$.fn.zCarousel = function(o) {
|
||||
o = $.extend({
|
||||
itemsPerPage: 1,
|
||||
circular: false
|
||||
}, o);
|
||||
|
||||
this.each(function() {
|
||||
var $self = $(this),
|
||||
$strip = $(".slider", $self),
|
||||
$lis = $strip.find(".panel"),
|
||||
$prev = $(o.btnPrev),
|
||||
$next = $(o.btnNext),
|
||||
prop = $("body").hasClass("html-rtl") ? "right" : "left",
|
||||
currentPos = 0,
|
||||
maxPos = Math.ceil($lis.length / o.itemsPerPage) - 1;
|
||||
|
||||
function render(pos) {
|
||||
if (o.circular) {
|
||||
currentPos = pos;
|
||||
if ($strip.hasClass("noslide")) {
|
||||
currentPos = (pos > maxPos+1) ? 1 : (pos < 1 ? maxPos+1 : pos);
|
||||
}
|
||||
} else {
|
||||
currentPos = Math.min(Math.max(0, pos), maxPos);
|
||||
}
|
||||
$strip.css(prop, currentPos * -100 + "%");
|
||||
$prev.toggleClass("disabled", currentPos == 0 && !o.circular);
|
||||
$next.toggleClass("disabled", currentPos == maxPos && !o.circular);
|
||||
|
||||
//wait for paint to clear the class. lame.
|
||||
setTimeout(function() {
|
||||
$strip.removeClass("noslide");
|
||||
}, 0);
|
||||
}
|
||||
|
||||
//wire up controls.
|
||||
$next.click(_pd(function() {
|
||||
render(currentPos+1);
|
||||
}));
|
||||
$prev.click(_pd(function() {
|
||||
render(currentPos-1);
|
||||
}));
|
||||
|
||||
// Strip text nodes so inline-block works properly.
|
||||
var cn = $strip[0].childNodes;
|
||||
for(var i = 0; i < cn.length; i++) {
|
||||
if (cn[i].nodeType == 3) {
|
||||
$strip[0].removeChild(cn[i]);
|
||||
};
|
||||
}
|
||||
|
||||
if (o.circular) {
|
||||
//pad the beginning with a page from the end vice-versa.
|
||||
$strip.prepend($lis.slice(-o.itemsPerPage).clone().addClass("cloned"))
|
||||
.append($lis.slice(0,o.itemsPerPage).clone().addClass("cloned"));
|
||||
render(o.itemsPerPage);
|
||||
//if we're outside the bounds, disable transitions and snap back to the beginning.
|
||||
$strip.bind("transitionend", function() {
|
||||
if (currentPos > maxPos+1 || currentPos < 1) {
|
||||
$strip.addClass("noslide");
|
||||
setTimeout(function() {
|
||||
render(currentPos);
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
render(0);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
})(jQuery);
|
|
@ -57,6 +57,7 @@ $(function() {
|
|||
};
|
||||
});
|
||||
|
||||
// this belongs in a more global place.
|
||||
$("img[data-defer-src]").each(function() {
|
||||
var $img = $(this);
|
||||
$img.attr('src', $img.attr('data-defer-src'));
|
||||
|
|
После Ширина: | Высота: | Размер: 336 B |
|
@ -1,86 +1,3 @@
|
|||
/**
|
||||
* zCarousel: like jCarouselLite, but good.
|
||||
* by potch
|
||||
*
|
||||
* handles fluid layouts like a champ!
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
|
||||
$.fn.zCarousel = function(o) {
|
||||
o = $.extend({
|
||||
itemsPerPage: 1,
|
||||
circular: false
|
||||
}, o);
|
||||
|
||||
this.each(function() {
|
||||
var $self = $(this),
|
||||
$strip = $(".slider", $self),
|
||||
$lis = $strip.find(".panel"),
|
||||
$prev = $(o.btnPrev),
|
||||
$next = $(o.btnNext),
|
||||
prop = $("body").hasClass("html-rtl") ? "right" : "left",
|
||||
currentPos = 0,
|
||||
maxPos = Math.ceil($lis.length / o.itemsPerPage) - 1;
|
||||
|
||||
function render(pos) {
|
||||
if (o.circular) {
|
||||
currentPos = pos;
|
||||
if ($strip.hasClass("noslide")) {
|
||||
currentPos = (pos > maxPos+1) ? 1 : (pos < 1 ? maxPos+1 : pos);
|
||||
}
|
||||
} else {
|
||||
currentPos = Math.min(Math.max(0, pos), maxPos);
|
||||
}
|
||||
$strip.css(prop, currentPos * -100 + "%");
|
||||
$prev.toggleClass("disabled", currentPos == 0 && !o.circular);
|
||||
$next.toggleClass("disabled", currentPos == maxPos && !o.circular);
|
||||
|
||||
//wait for paint to clear the class. lame.
|
||||
setTimeout(function() {
|
||||
$strip.removeClass("noslide");
|
||||
}, 0);
|
||||
}
|
||||
|
||||
//wire up controls.
|
||||
$next.click(_pd(function() {
|
||||
render(currentPos+1);
|
||||
}));
|
||||
$prev.click(_pd(function() {
|
||||
render(currentPos-1);
|
||||
}));
|
||||
|
||||
// Strip text nodes so inline-block works properly.
|
||||
var cn = $strip[0].childNodes;
|
||||
for(var i = 0; i < cn.length; i++) {
|
||||
if (cn[i].nodeType == 3) {
|
||||
$strip[0].removeChild(cn[i]);
|
||||
};
|
||||
}
|
||||
|
||||
if (o.circular) {
|
||||
//pad the beginning with a page from the end vice-versa.
|
||||
$strip.prepend($lis.slice(-o.itemsPerPage).clone().addClass("cloned"))
|
||||
.append($lis.slice(0,o.itemsPerPage).clone().addClass("cloned"));
|
||||
render(o.itemsPerPage);
|
||||
//if we're outside the bounds, disable transitions and snap back to the beginning.
|
||||
$strip.bind("transitionend", function() {
|
||||
if (currentPos > maxPos+1 || currentPos < 1) {
|
||||
$strip.addClass("noslide");
|
||||
setTimeout(function() {
|
||||
render(currentPos);
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
render(0);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
})(jQuery);
|
||||
|
||||
|
||||
$(document).ready(function(){
|
||||
if ($(".detail").length) {
|
||||
initDetail();
|
||||
|
|
13
settings.py
|
@ -385,16 +385,19 @@ MINIFY_BUNDLES = {
|
|||
),
|
||||
'zamboni/impala': (
|
||||
'css/impala/base.css',
|
||||
'css/legacy/jquery-lightbox.css',
|
||||
'css/impala/site.less',
|
||||
'css/impala/typography.less',
|
||||
'css/impala/header.less',
|
||||
'css/global/headerfooter.css',
|
||||
'css/impala/header.less',
|
||||
'css/impala/footer.less',
|
||||
'css/impala/moz-tab.css',
|
||||
'css/impala/hovercards.less',
|
||||
'css/impala/toplist.less',
|
||||
'css/impala/carousel.less',
|
||||
'css/impala/reviews.less',
|
||||
# 'css/zamboni/amo_headerfooter.css',
|
||||
'css/impala/buttons.less',
|
||||
'css/impala/addon_details.less',
|
||||
),
|
||||
'zamboni/discovery-pane': (
|
||||
'css/zamboni/discovery-pane.css',
|
||||
|
@ -465,9 +468,10 @@ MINIFY_BUNDLES = {
|
|||
'js/global/menu.js',
|
||||
),
|
||||
'impala': (
|
||||
'js/lib/jquery-1.4.2.min.js',
|
||||
'js/lib/jquery-1.6.min.js',
|
||||
'js/lib/jquery-ui/custom-1.8.5.min.js',
|
||||
'js/lib/underscore-min.js',
|
||||
'js/impala/carousel.js',
|
||||
'js/zamboni/browser.js',
|
||||
'js/amo2009/addons.js',
|
||||
'js/zamboni/init.js',
|
||||
|
@ -490,7 +494,7 @@ MINIFY_BUNDLES = {
|
|||
'js/lib/jquery-ui/ui.lightbox.js',
|
||||
'js/get-satisfaction-v2.js',
|
||||
'js/zamboni/contributions.js',
|
||||
'js/zamboni/addon_details.js',
|
||||
'js/impala/addon_details.js',
|
||||
'js/zamboni/reviews.js',
|
||||
|
||||
# Personas
|
||||
|
@ -518,6 +522,7 @@ MINIFY_BUNDLES = {
|
|||
'js/zamboni/browser.js',
|
||||
'js/zamboni/init.js',
|
||||
'js/zamboni/format.js',
|
||||
'js/impala/carousel.js',
|
||||
|
||||
# Add-ons details
|
||||
'js/zamboni/buttons.js',
|
||||
|
|
|
@ -67,28 +67,27 @@
|
|||
<a href="http://mozilla.org/"><img src="{{ media('img/zamboni/mozilla-tab.png') }}"></a>
|
||||
</div>
|
||||
<div class="amo-header">
|
||||
<div id="aux-nav" role="navigation" class="c">
|
||||
{% block aux_nav %}
|
||||
<ul id="other-apps" class="change"
|
||||
title="{{ _('Find add-ons for other applications') }}">
|
||||
<li>
|
||||
<a href="#" class="controller">{{ _('Other Applications') }}</a>
|
||||
<ul>
|
||||
{% for app in amo.APP_USAGE %}
|
||||
{% if app != request.APP %}
|
||||
<li id="app-{{ app.short }}" class="{{ app.short }}">
|
||||
<a href="{{ locale_url(app.short) }}">{{ app.pretty }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
<nav id="aux-nav" role="navigation" class="menu-nav">
|
||||
<ul class="c">
|
||||
{% if not settings.READ_ONLY %}
|
||||
{% include "impala/user_login.html" %}
|
||||
{% endif %}
|
||||
{% block aux_nav %}
|
||||
<li>
|
||||
<a href="#" class="controller" title="{{ _('Find add-ons for other applications') }}">{{ _('Other Applications') }}</a>
|
||||
<ul>
|
||||
{% for app in amo.APP_USAGE %}
|
||||
{% if app != request.APP %}
|
||||
<li id="app-{{ app.short }}" class="{{ app.short }}">
|
||||
<a href="{{ locale_url(app.short) }}">{{ app.pretty }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
{% endblock aux_nav %}
|
||||
</ul>
|
||||
{% endblock aux_nav %}
|
||||
{% if not settings.READ_ONLY %}
|
||||
{% include "user_login.html" %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</nav>
|
||||
<div class="header-search" role="search">
|
||||
{% block search_form %}
|
||||
{% include 'impala/search.html' %}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
<li class="account">
|
||||
{% if user.is_authenticated() %}
|
||||
<a href="#" class="user" title="{{ user.email }}">
|
||||
{{ user.get_profile().welcome_name }}
|
||||
</a>
|
||||
{% if account_links %}
|
||||
<ul>
|
||||
{% for link in account_links %}
|
||||
<li><a href="{{ link.href }}">{{ link.text }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{# TODO(jbalogh): reverse #}
|
||||
{% trans reg="/users/register", login=login_link() %}
|
||||
<a href="{{ reg }}">Register</a> or <a href="{{ login }}">Log in</a>
|
||||
{% endtrans %}
|
||||
{% endif %}
|
||||
</li>
|
||||
|
||||
{% if user.is_authenticated() %}
|
||||
{% if tools_links and tools_links|count > 1 %}
|
||||
<li class="tools">
|
||||
<a href="#">{{ _('Tools') }}</a>
|
||||
<ul>
|
||||
{% for link in tools_links %}
|
||||
<li><a href="{{ link.href }}">{{ link.text }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
{% else %}
|
||||
<p class="context tools">
|
||||
<a href="{{ tools_links[0].href }}">{{ tools_links[0].text }}</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endif %}
|