зеркало из https://github.com/mozilla/kitsune.git
topic page tabs added
This commit is contained in:
Родитель
0f8f621565
Коммит
1a15d6d7f2
|
@ -312,6 +312,7 @@ PIPELINE_JS = {
|
|||
'sumo/js/protocol-details-init.js',
|
||||
'sumo/js/protocol-modal-init.js',
|
||||
'sumo/js/protocol-notification-init.js',
|
||||
'sumo/js/sumo-tabs.js',
|
||||
),
|
||||
'output_filename': 'build/common-min.js'
|
||||
},
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{% extends "base.html" %}
|
||||
{% from 'products/includes/topic_macros.html' import topic_sidebar %}
|
||||
{% from 'products/includes/topic_macros.html' import topic_sidebar, topic_tabs %}
|
||||
{% from 'includes/common_macros.html' import download_firefox %}
|
||||
{% set crumbs = [(url('products.product', slug=product.slug), pgettext('DB: products.Product.title', product.title))] %}
|
||||
{% if subtopic %}
|
||||
|
@ -53,16 +53,10 @@
|
|||
{{ pgettext('DB: products.Topic.title', subtopic.title) }}
|
||||
</h1>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if product.slug == 'firefox' %}
|
||||
<div class="sumo-article-header--meta">
|
||||
{{ download_firefox() }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</header>
|
||||
|
||||
{# Show the description if it is different than the title. Otherwise, don't bother. #}
|
||||
{% if (subtopic and subtopic.title != subtopic.description) or (not subtopic and topic.title != topic.description) %}
|
||||
<p class="topic-description">
|
||||
<p class="topic-description color-heading text-body-lg">
|
||||
{% if subtopic %}
|
||||
{{ pgettext('DB: products.Topic.description', subtopic.description) }}
|
||||
{% else %}
|
||||
|
@ -70,7 +64,17 @@
|
|||
{% endif %}
|
||||
</p>
|
||||
{% endif %}
|
||||
<hr />
|
||||
</div>
|
||||
{% if product.slug == 'firefox' %}
|
||||
<div class="sumo-article-header--meta">
|
||||
{{ download_firefox() }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</header>
|
||||
|
||||
{{ topic_tabs(topics[:10], subtopics, product, topic, subtopic) }}
|
||||
|
||||
|
||||
|
||||
|
||||
<section class="topic-list">
|
||||
|
|
|
@ -71,18 +71,27 @@
|
|||
<a class="sidebar-nav--link {% if selected_topic == topic %}selected{% endif %}" href="{{ topic_url }}" data-event-category="link click" data-event-action="topic sidebar" data-event-label="{{topic.title}}">
|
||||
{{ pgettext('DB: products.Topic.title', topic.title) }}
|
||||
</a>
|
||||
{% if selected_topic == topic %}
|
||||
<ul class="sidebar-nav--sublist">
|
||||
{% for subtopic in subtopics %}
|
||||
{% set subtopic_url = url('products.subtopics', product_slug=product.slug, topic_slug=topic.slug, subtopic_slug=subtopic.slug) %}
|
||||
<li class="sidebar-nav--subitem" {{ selected_subtopic|class_selected(subtopic) }}>
|
||||
<a class="sidebar-nav--sublink" href="{{ subtopic_url }}" data-event-category="link click" data-event-action="subtopic sidebar" data-event-label="{{subtopic.title}}">
|
||||
{{ pgettext('DB: products.Topic.title', subtopic.title) }}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</nav>
|
||||
{%- endmacro %}
|
||||
|
||||
|
||||
{% macro topic_tabs(topics, subtopics, product, selected_topic=None, selected_subtopic=None) -%}
|
||||
<nav class="tabs">
|
||||
<ul class="tabs--list subtopics">
|
||||
<li class="tabs--item">
|
||||
<a class="tabs--link {% if selected_subtopic == None %}is-active{% endif %}" href="{{ topic_url }}">
|
||||
<span>{{ _('All articles and threads') }}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% for subtopic in subtopics %}
|
||||
{% set subtopic_url = url('products.subtopics', product_slug=product.slug, topic_slug=topic.slug, subtopic_slug=subtopic.slug) %}
|
||||
<li class="tabs--item">
|
||||
<a class="tabs--link {% if selected_subtopic == subtopic %}is-active{% endif %}" href="{{ subtopic_url }}" data-event-category="link click" data-event-action="subtopic sidebar" data-event-label="{{subtopic.title}}">
|
||||
<span>{{ pgettext('DB: products.Topic.title', subtopic.title) }}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
const container = document.querySelector('.tabs')
|
||||
const primary = container.querySelector('.tabs--list')
|
||||
const primaryItems = container.querySelectorAll('.tabs--list > li:not(.tabs--item-more)')
|
||||
container.classList.add('is-js-enhanced')
|
||||
|
||||
// insert "more" button and duplicate the list
|
||||
|
||||
primary.insertAdjacentHTML('beforeend', `
|
||||
<li class="tabs--item-more">
|
||||
<button class="tabs--button" type="button" aria-haspopup="true" aria-expanded="false">
|
||||
More
|
||||
</button>
|
||||
<ul class="tabs--dropdown elevation-01">
|
||||
${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 doAdapt = () => {
|
||||
// reveal all items for the calculation
|
||||
allItems.forEach((item) => {
|
||||
item.classList.remove('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
|
||||
|
||||
// is-hidden Secondary on the outside click
|
||||
|
||||
document.addEventListener('click', (e) => {
|
||||
let el = e.target
|
||||
while(el) {
|
||||
if(el === secondary || el === moreBtn) {
|
||||
return;
|
||||
}
|
||||
el = el.parentNode
|
||||
}
|
||||
container.classList.remove('dropdown-is-open')
|
||||
moreBtn.setAttribute('aria-expanded', false)
|
||||
})
|
|
@ -53,6 +53,10 @@ h1, h2, h3, h4, h5, h6 {
|
|||
}
|
||||
}
|
||||
|
||||
.color-heading {
|
||||
color: var(--color-heading);
|
||||
}
|
||||
|
||||
// Type scale defined in includes/mixins/_typography.scss
|
||||
h1,
|
||||
.text-display-xxl {
|
||||
|
@ -106,22 +110,22 @@ h5, h6, .text-display-sm {
|
|||
color: var(--color-inverse);
|
||||
}
|
||||
|
||||
.body-lg {
|
||||
.text-body-lg {
|
||||
@include p.font-size(18px);
|
||||
@include c.line-height(28px);
|
||||
}
|
||||
|
||||
.body-md {
|
||||
.text-body-md {
|
||||
@include p.font-size(16px);
|
||||
@include c.line-height(28px);
|
||||
}
|
||||
|
||||
.body-sm {
|
||||
.text-body-sm {
|
||||
@include p.font-size(14px);
|
||||
@include c.line-height(22px);
|
||||
}
|
||||
|
||||
.body-xs {
|
||||
.text-body-xs {
|
||||
@include p.font-size(12px);
|
||||
@include c.line-height(18px);
|
||||
}
|
||||
|
|
|
@ -6,3 +6,4 @@
|
|||
@forward 'card-grid';
|
||||
@forward 'modal';
|
||||
@forward 'notifications';
|
||||
@forward 'tabs';
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
// Tabs
|
||||
//
|
||||
// Tab component used on the topic listing pages. See
|
||||
// [this CSS-tricks article](https://css-tricks.com/container-adapting-tabs-with-more-button/)
|
||||
// for a detailed explanation of how it was built.
|
||||
//
|
||||
// Markup: ../../../../../../../styleguide/styleguide-examples/tabs.njk
|
||||
//
|
||||
// Weight: 8
|
||||
//
|
||||
// Style guide: tabs
|
||||
|
||||
@use '../config' as c;
|
||||
@use '../protocol' as p;
|
||||
|
||||
.tabs {
|
||||
position: relative;
|
||||
box-shadow: inset 0 -1px 0 var(--color-marketing-gray-03);
|
||||
margin-bottom: 24px;
|
||||
|
||||
&:not(.is-js-enhanced) {
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.is-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&--list {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
&--link,
|
||||
&--button {
|
||||
appearance: none;
|
||||
white-space: nowrap;
|
||||
text-align: left;
|
||||
border: 0 none;
|
||||
display: block;
|
||||
color: var(--color-text);
|
||||
text-decoration: none;
|
||||
background-color: transparent;
|
||||
@include c.text-body-sm;
|
||||
|
||||
span {
|
||||
display: block;
|
||||
padding: 16px 0;
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: var(--color-link);
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
color: var(--color-link);
|
||||
font-weight: bold;
|
||||
|
||||
span {
|
||||
box-shadow: inset 0 -2px 0 var(--color-link);
|
||||
}
|
||||
}
|
||||
|
||||
&:active {
|
||||
color: var(--color-link);
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
&--button {
|
||||
padding: 16px 0;
|
||||
|
||||
&:after {
|
||||
display: inline-flex;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
margin-left: 4px;
|
||||
background-image: c.svg-url('<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18 10"><path fill="none" vector-effect="non-scaling-stroke" stroke="#42435A" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M1 1l8 8 8-8"/></svg>');
|
||||
background-repeat: no-repeat;
|
||||
background-size: 12px 12px;
|
||||
transition: transform 0.2s;
|
||||
content: "";
|
||||
}
|
||||
}
|
||||
|
||||
&.dropdown-is-open {
|
||||
.tabs--button:after {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.tabs--dropdown {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
&--dropdown {
|
||||
max-width: 100%;
|
||||
min-width: 10em;
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
right: 0;
|
||||
border-radius: var(--global-radius);
|
||||
animation: tabs-dropdown 0.2s;
|
||||
|
||||
.tabs--item {
|
||||
border-top: 1px solid var(--color-border);
|
||||
background-color: var(--page-bg);
|
||||
|
||||
span {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.tabs--link {
|
||||
padding: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
@media #{p.$mq-md} {
|
||||
margin-bottom: 48px;
|
||||
|
||||
&--link,
|
||||
&--button {
|
||||
@include c.text-body-md;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// keyframes
|
||||
|
||||
@keyframes tabs-dropdown {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(-1em);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
|
@ -1,9 +1,29 @@
|
|||
@use '../config' as c;
|
||||
@use '../protocol' as p;
|
||||
|
||||
.topic-article {
|
||||
margin-bottom: 24px;
|
||||
|
||||
@media #{p.$mq-md} {
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
@media #{p.$mq-md} {
|
||||
margin-bottom: 48px;
|
||||
}
|
||||
}
|
||||
|
||||
.sumo-article-header {
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
|
||||
&--text {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
&--meta {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
@media #{p.$mq-md} {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
margin-bottom: 48px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,24 +31,6 @@
|
|||
display: none;
|
||||
}
|
||||
|
||||
.sumo-article-header {
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
|
||||
&--text {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
&--meta {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
@media #{p.$mq-md} {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.documents-product-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
|
@ -47,7 +47,9 @@
|
|||
"static/protocol/js/protocol-notification-bar.js",
|
||||
"static/sumo/js/protocol-nav.js",
|
||||
"static/sumo/js/protocol-details-init.js",
|
||||
"static/sumo/js/show-fx-download.js"
|
||||
"static/sumo/js/show-fx-download.js",
|
||||
"static/sumo/js/sumo-tabs.js"
|
||||
|
||||
],
|
||||
"homepage": "../../../../../styleguide/styleguide-examples/styleguide-index.md",
|
||||
"builder": "kss-template"
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
<nav class="tabs">
|
||||
<ul class="tabs--list subtopics">
|
||||
<li class="tabs--item">
|
||||
<a class="tabs--link is-active" href="#">
|
||||
<span>All articles and threads</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="tabs--item">
|
||||
<a class="tabs--link" href="#">
|
||||
<span>Bookmarks and Tabs</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="tabs--item">
|
||||
<a class="tabs--link" href="#">
|
||||
<span>Tips and Tricks</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<div style="height:200px"><!-- necessary for z-index issues in styleguide iframes -->
|
Загрузка…
Ссылка в новой задаче