Skip to content

Commit

Permalink
reorganize the tabbed portion of the localization dashboard
Browse files Browse the repository at this point in the history
  • Loading branch information
escattone committed Nov 27, 2023
1 parent 5ed51a6 commit 5242bd8
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 110 deletions.
60 changes: 29 additions & 31 deletions kitsune/dashboards/jinja2/dashboards/includes/macros.html
Original file line number Diff line number Diff line change
@@ -1,37 +1,43 @@
{% macro print_readout_body(readout, locale=None, max_rows=10, product=None) %}
{% if not readout.hide_readout %}
<ul class="readout-modes" data-slug="{{ readout.slug }}">
{% for key, name in readout.modes %}
<li class="mode{% if key == readout.default_mode %} active
{% endif %}" data-url="{{ url('dashboards.wiki_rows',
readout.slug)|urlparams(max=max_rows, mode=key, locale=locale, product=product.slug) }}">
<a href="#">{{ name }}</a>
</li>
{% endfor %}
</ul>
{% if readout.description %}
<p>
{{ readout.description }}
</p>
{% endif %}
<table class="documents" id="{{ readout.slug }}-table">
{{ readout.render(max_rows=max_rows)|safe }}
</table>
<div class="table-footer">
<a href="{{ readout.get_absolute_url(request.LANGUAGE_CODE, product) }}">{{ readout.details_link_text }}</a>
</div>
{% endif %}
{% endmacro %}

{% macro print_readout(readout, locale=None, max_rows=10, product=None) %}
{% if not readout.hide_readout %}
<details class="h2" open="open">
<details open>
<summary class="with-mode-selectors">
<a id="{{ readout.slug }}">{{ readout.title }}</a>
</summary>
<ul class="readout-modes" data-slug="{{ readout.slug }}">
{% for key, name in readout.modes %}
<li class="mode{% if key == readout.default_mode %} active
{% endif %}" data-url="{{ url('dashboards.wiki_rows',
readout.slug)|urlparams(max=max_rows, mode=key, locale=locale, product=product.slug) }}">
<a href="#">{{ name }}</a>
</li>
{% endfor %}
</ul>
{% if readout.description %}
<p>
{{ readout.description }}
</p>
{% endif %}
<table class="documents" id="{{ readout.slug }}-table">
{{ readout.render(max_rows=max_rows)|safe }}
</table>
<div class="table-footer">
<a href="{{ readout.get_absolute_url(request.LANGUAGE_CODE, product) }}">{{ readout.details_link_text }}</a>
</div>
{{ print_readout_body(readout, locale, max_rows, product) }}
</details>
{% endif %}
{% endmacro %}

{% macro overview_section(readouts, printed_rows) %}
{# printed_rows is a tuple of pairs, (row, should_color), like so:
((row1, True/False), (row2, True/False), ... etc) #}
<details class="h2" open="open">
<details open>
<summary>{{ _('Overview') }}</summary>
<table class="overview l10n-overview">
{% for row, should_color in printed_rows %}
Expand All @@ -43,7 +49,7 @@
</td>
<td>
{% trans numerator=number(row.numerator), denominator=number(row.denominator) %}
{{ numerator }}
{{ numerator }}
<small>of {{ denominator }}</small>
{% endtrans %}
</td>
Expand Down Expand Up @@ -90,14 +96,6 @@
<td></td>
</tr>
</table>
<div id="overview-options" class="choice-list">
<label>{{ _('Jump to:') }}</label>
<ul>
{% for slug, readout in readouts.items() if readout.short_title %}
<li><a href="#{{ slug }}">{{ readout.short_title }}</a></li>
{% endfor %}
</ul>
</div>
</details>
{% endmacro %}

Expand Down
32 changes: 17 additions & 15 deletions kitsune/dashboards/jinja2/dashboards/localization.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{% extends "base.html" %}
{% from "dashboards/includes/macros.html" import print_readout, overview_section, product_choice_list, print_subscription_menu with context %}
{% from "dashboards/includes/macros.html" import print_readout_body, overview_section, product_choice_list, print_subscription_menu with context %}
{% from "dashboards/includes/macros.html" import localization_sidebar_nav %}
{% set title = _('[{locale}][{product}] Localization Dashboard')|fe(locale=current_locale, product=pgettext('DB: products.Product.title', product.title) if product else _('All Products')) %}
{% set scripts = ('wiki', 'wiki.dashboard') %}
Expand Down Expand Up @@ -83,22 +83,24 @@ <h2>{{ _('Locale:') }} {{ current_locale_name }}</h2>
(overview_rows['all'], True),
(overview_rows['templates'], True))) }}

<div id="stats-tabs" data-ui-type="tabbed-view">
<ul class="cf" data-tab-role="tabs">
<li><a href="#">{{ _('Localization') }}</a></li>
<li><a href="#">{{ _('Review') }}</a></li>
<nav class="localization tabs">
<ul class="tabs--list">
{% for readout in readouts.values() %}
<li class="tabs--item">
<button class="tabs--link{% if readout.slug == 'most-visited-translations' %} is-active{% endif %}" data-tab-content-id="{{ readout.slug }}" id="{{ readout.slug }}">
<span>{{ readout.title }}</span>
</button>
</li>
{% endfor %}
</ul>
<div data-tab-role="panels">
<div>
{{ print_readout(readouts['most-visited-translations'], max_rows=20, product=product) }}
</div>
<div>
{{ print_readout(readouts['unreviewed'], max_rows=10, product=product) }}
</div>
</div>
</div>
</nav>

{% for readout in readouts.values() %}
<section class="localization tabs--content{% if readout.slug == 'most-visited-translations' %} is-active{% endif %}" id="tab-{{ readout.slug }}">
{{ print_readout_body(readout, max_rows=20 if readout.slug == 'most-visited-translations' else 10, product=product) }}
</section>
{% endfor %}

{{ print_readout(readouts['template-translations'], max_rows=10, product=product) }}
</article>
</div>
{% endblock %}
Expand Down
2 changes: 1 addition & 1 deletion kitsune/dashboards/readouts.py
Original file line number Diff line number Diff line change
Expand Up @@ -1210,7 +1210,7 @@ def _format_row(self, row):
# L10n Dashboard tables that have their own whole-page views:
L10N_READOUTS = OrderedDict(
(t.slug, t) # type: ignore
for t in [MostVisitedTranslationsReadout, TemplateTranslationsReadout, UnreviewedReadout]
for t in [MostVisitedTranslationsReadout, UnreviewedReadout, TemplateTranslationsReadout]
)

# Contributors ones:
Expand Down
2 changes: 1 addition & 1 deletion kitsune/dashboards/tests/test_templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class LocalizationDashTests(TestCase):
@staticmethod
def _assert_readout_contains(doc, slug, contents):
"""Assert `doc` contains `contents` within the `slug` readout."""
html = doc("a#" + slug).closest("details").html()
html = doc("section#tab-" + slug).html()
assert contents in html, "'" + contents + "' is not in the following: " + html

def test_render(self):
Expand Down
32 changes: 32 additions & 0 deletions kitsune/sumo/static/sumo/js/dashboards.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
initNeedsChange();
initAnnouncements();
initL10nStringsStats();
initLocalizationTabs();
setProgressBarWidth();
}

Expand Down Expand Up @@ -203,5 +204,36 @@
}
}

function initLocalizationTabs() {
const tabs = document.querySelectorAll('.dashboards nav.localization.tabs .tabs--link');
const tabContents = document.querySelectorAll('.dashboards .localization.tabs--content');

tabs.forEach(function(tab) {
tab.addEventListener('click', function() {
// Remove active class from all tabs and hide all tab contents
tabs.forEach(function(tab) {
tab.classList.remove('is-active');
});

tabContents.forEach(function(content) {
content.classList.remove('is-active');
});

// Add active class to the selected tab and show its content
tab.classList.add('is-active');
const targetContent = document.getElementById('tab-' + tab.getAttribute('data-tab-content-id'));
if (targetContent) {
targetContent.classList.add('is-active');
}

window.location.hash = tab.id;
});
});

if (window.location.hash) {
$(window.location.hash).trigger('click');
}
};

$(init);
})(jQuery);
119 changes: 60 additions & 59 deletions kitsune/sumo/static/sumo/js/sumo-tabs.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
export default function tabsInit() {
const container = document.querySelector('.tabs')
const container = document.querySelector('.tabs');

// insert "more" button and duplicate the list
if (container) {

const existingMoreBtn = container.querySelector('.tabs--item-more')
const primary = container.querySelector('.tabs--list')
const primaryItems = container.querySelectorAll('.tabs--list > li:not(.tabs--item-more)')
container.classList.add('is-js-enhanced')
const existingMoreBtn = container.querySelector('.tabs--item-more');
const primary = container.querySelector('.tabs--list');
const primaryItems = container.querySelectorAll('.tabs--list > li:not(.tabs--item-more)');
container.classList.add('is-js-enhanced');

// reset in the event that this is run twice.
if (existingMoreBtn) {
Expand All @@ -23,70 +23,71 @@ export default function tabsInit() {
${primary.innerHTML}
</ul>
</li>
`)
const secondary = container.querySelector('.tabs--dropdown')
const secondaryItems = secondary.querySelectorAll('li')
const allItems = container.querySelectorAll('li')
const moreLi = primary.querySelector('.tabs--item-more')
const moreBtn = moreLi.querySelector('button')
moreBtn.addEventListener('click', (e) => {
e.preventDefault()
container.classList.toggle('dropdown-is-open')
moreBtn.setAttribute('aria-expanded', container.classList.contains('dropdown-is-open'))
})
`)

// adapt tabs
const secondary = container.querySelector('.tabs--dropdown');
const secondaryItems = secondary.querySelectorAll('li');
const allItems = container.querySelectorAll('li');
const moreLi = primary.querySelector('.tabs--item-more');
const moreBtn = moreLi.querySelector('button');
moreBtn.addEventListener('click', (e) => {
e.preventDefault();
container.classList.toggle('dropdown-is-open');
moreBtn.setAttribute('aria-expanded', container.classList.contains('dropdown-is-open'));
});

const doAdapt = () => {
// reveal all items for the calculation
allItems.forEach((item) => {
item.classList.remove('is-hidden')
})
// adapt tabs

// is-hidden items that won't fit in the Primary
let stopWidth = moreBtn.offsetWidth
let hiddenItems = []
const primaryWidth = primary.offsetWidth
primaryItems.forEach((item, i) => {
if(primaryWidth >= stopWidth + item.offsetWidth) {
stopWidth += item.offsetWidth
} else {
item.classList.add('is-hidden')
hiddenItems.push(i)
}
})
const doAdapt = () => {
// reveal all items for the calculation
allItems.forEach((item) => {
item.classList.remove('is-hidden');
});

// toggle the visibility of More button and items in Secondary
if(!hiddenItems.length) {
moreLi.classList.add('is-hidden')
container.classList.remove('dropdown-is-open')
moreBtn.setAttribute('aria-expanded', false)
}
else {
secondaryItems.forEach((item, i) => {
if(!hiddenItems.includes(i)) {
item.classList.add('is-hidden')
// is-hidden items that won't fit in the Primary
let stopWidth = moreBtn.offsetWidth;
let hiddenItems = [];
const primaryWidth = primary.offsetWidth;
primaryItems.forEach((item, i) => {
if(primaryWidth >= stopWidth + item.offsetWidth) {
stopWidth += item.offsetWidth;
} else {
item.classList.add('is-hidden');
hiddenItems.push(i);
}
})
});

// toggle the visibility of More button and items in Secondary
if (!hiddenItems.length) {
moreLi.classList.add('is-hidden');
container.classList.remove('dropdown-is-open');
moreBtn.setAttribute('aria-expanded', false);
}
else {
secondaryItems.forEach((item, i) => {
if(!hiddenItems.includes(i)) {
item.classList.add('is-hidden');
}
});
}
}
}

doAdapt() // adapt immediately on load
window.addEventListener('resize', doAdapt) // adapt on window resize
doAdapt(); // adapt immediately on load
window.addEventListener('resize', doAdapt); // adapt on window resize

// is-hidden Secondary on the outside click
// is-hidden Secondary on the outside click

document.addEventListener('click', (e) => {
let el = e.target
while(el) {
if(el === secondary || el === moreBtn) {
return;
document.addEventListener('click', (e) => {
let el = e.target;
while(el) {
if(el === secondary || el === moreBtn) {
return;
}
el = el.parentNode;
}
el = el.parentNode
}
container.classList.remove('dropdown-is-open')
moreBtn.setAttribute('aria-expanded', false)
})
container.classList.remove('dropdown-is-open');
moreBtn.setAttribute('aria-expanded', false);
});

}
};
Expand Down
31 changes: 30 additions & 1 deletion kitsune/sumo/static/sumo/scss/components/_dashboards.scss
Original file line number Diff line number Diff line change
Expand Up @@ -182,4 +182,33 @@
&:visited {
color: inherit;
}
}
}

.dashboards {
button.tabs--link > span, details > summary {
font-size: 1.5rem;
}

details > summary {
font-weight: bold;
}

.tabs--content:not(.tabs--content.is-active) {
display: none;
}

nav.tabs {
button.tabs--link:focus:not(:focus-visible) {
box-shadow: none;
}

button.tabs--link:hover {
cursor: pointer;
}
}

details {
padding-top: p.$spacing-lg;
padding-bottom: p.$spacing-lg;
}
}
4 changes: 2 additions & 2 deletions kitsune/sumo/static/sumo/scss/components/_wiki.scss
Original file line number Diff line number Diff line change
Expand Up @@ -1197,8 +1197,8 @@ article {
}

#get-involved-box {
margin-top: 100px;
text-align: center;
margin-top: p.$spacing-lg;
margin-bottom: p.$spacing-2xl;

.btn {
font-size: p.$spacing-md;
Expand Down

0 comments on commit 5242bd8

Please sign in to comment.