- <footer class="ui basic center aligned segment">
+ <footer class="ui basic center aligned segment{% if login.getCompactMenu() %} extended{% endif %}">
<div class="row">
- <nav class="ui horizontal bulleted link list">
+ <div class="ui horizontal bulleted link list">
<a href="https://galette.eu" class="item">
<i class="icon globe europe" aria-hidden="true"></i>
{{ _T("Website") }}
<i class="icon mastodon" aria-hidden="true"></i>
@galette
</a>
- </nav>
+ </div>
</div>
<div class="row">
- <nav class="ui horizontal bulleted link list">
+ <div class="ui horizontal bulleted link list">
<a id="copyright" href="https://galette.eu/" class="item">
<i class="icon cookie bite" aria-hidden="true"></i>
Galette {{ constant('GALETTE_DISPLAY_VERSION') }}
{{ _T("System information") }}
</a>
{% endif %}
- </nav>
+ </div>
{% if login.isLogged() and cur_route == 'dashboard' %}
{# Comply with the Twemoji project's requirements about attribution #}
<!--
</div>
{% else %}
{% if not login.getCompactMenu() %}
- <div class="{{ component_classes }}">
+ <nav class="{{ component_classes }}" aria-label="{{ _T('User menu') }}">
<div class="ui item">
<i class="user circle big icon" aria-hidden="true"></i>
{{ login.loggedInAs()|raw }}
title="{% if login.isDarkModeEnabled() %}{{ _T("Disable dark mode") }}{% else %}{{ _T("Enable dark mode") }}{% endif %}"
>
<i class="icon adjust" aria-hidden="true"></i>
- <span class="displaynone">{% if login.isDarkModeEnabled() %}{{ _T("Disable dark mode") }}{% else %}{{ _T("Enable dark mode") }}{% endif %}</span>
+ <span class="visually-hidden">{% if login.isDarkModeEnabled() %}{{ _T("Disable dark mode") }}{% else %}{{ _T("Enable dark mode") }}{% endif %}</span>
</a>
<a
class="ui {% if login.isImpersonated() %}purple{% else %}red{% endif %} icon button"
data-position="bottom right"
>
<i class="icon {% if login.isImpersonated() %}user secret{% else %}sign out alt{% endif %}" aria-hidden="true"></i>
- <span class="displaynone">{% if login.isImpersonated() %}{{ _T("Unimpersonate") }}{% else %}{{ _T("Log off") }}{% endif %}</span>
+ <span class="visually-hidden">{% if login.isImpersonated() %}{{ _T("Unimpersonate") }}{% else %}{{ _T("Log off") }}{% endif %}</span>
</a>
</div>
</div>
</div>
- </div>
+ </nav>
{% include "elements/modes.html.twig" %}
{% else %}
{% set component_classes = "ui vertical centered tiny icon fluid menu" %}
- <div id="logoutmenu" class="{{ component_classes }}">
+ <nav id="logoutmenu" class="{{ component_classes }}" aria-label="{{ _T('User menu') }}">
<div class="ui dropdown navigation item no-touch tooltip" data-html="{{ login.loggedInAs()|raw }}" data-position="right center">
<i class="user circle icon" aria-hidden="true"></i>
- <span class="displaynone">{{ login.loggedInAs()|raw }}</span>
+ <span class="visually-hidden">{{ login.loggedInAs()|raw }}</span>
<i class="dropdown icon" aria-hidden="true"></i>
<div class="menu">
<div class="item">
data-position="right center"
>
<i class="icon adjust" aria-hidden="true"></i>
- <span class="displaynone">{% if login.isDarkModeEnabled() %}{{ _T("Disable dark mode") }}{% else %}{{ _T("Enable dark mode") }}{% endif %}</span>
+ <span class="visually-hidden">{% if login.isDarkModeEnabled() %}{{ _T("Disable dark mode") }}{% else %}{{ _T("Enable dark mode") }}{% endif %}</span>
</a>
<a
class="item{% if login.isImpersonated() %} purple{% else %} red{% endif %}"
data-position="right center"
>
<i class="icon {% if login.isImpersonated() %}user secret{% else %}sign out alt{% endif %}" aria-hidden="true"></i>
- <span class="displaynone">{% if login.isImpersonated() %}{{ _T("Unimpersonate") }}{% else %}{{ _T("Log off") }}{% endif %}</span>
+ <span class="visually-hidden">{% if login.isImpersonated() %}{{ _T("Unimpersonate") }}{% else %}{{ _T("Log off") }}{% endif %}</span>
</a>
- </div>
+ </nav>
{% endif %}
{% endif %}
{% endif %}
-<aside id="sidemenu" class="ui computer only toc{% if login.getCompactMenu() %} compact_menu{% endif %}">
+<aside id="sidemenu" class="ui computer toc{% if login.getCompactMenu() %} compact_menu{% endif %}">
{% include "elements/logged_user.html.twig" with {
ui: "menu"
} %}
</div>
{% endif %}
- <div class="ui vertical{% if not login.getCompactMenu() %} accordion compact{% else %} tiny icon{% endif %} fluid menu">
+ <nav class="ui vertical{% if not login.getCompactMenu() %} accordion compact{% else %} tiny icon{% endif %} fluid menu" aria-label="{{ _T('Main menu') }}">
{% set mode = login.getCompactMenu() ? "compact" : "default" %}
{% include "elements/navigation/navigation_items.html.twig" with {
mode: mode
} %}
- </div>
+ </nav>
<div class="ui basic fitted segment">
<div class="ui toggle mini checkbox">
- <div id="sidebarmenu" class="ui simple left vertical accordion menu sidebar">
+ <nav id="sidebarmenu" class="ui simple left vertical accordion menu sidebar">
{% if not login.isLogged() %}
{% if cur_route != "login" %}
{% import "macros.twig" as menus_macros %}
<div class="ui basic center aligned segment">
{% include "elements/modes.html.twig" %}
</div>
- </div>
+ </nav>
<header id="top-navbar" class="ui top fixed menu">
- <div class="ui fluid container">
- <a class="toc item" tabindex="0">
- <i class="sidebar icon" aria-hidden="true"></i>
- <span class="displaynone">{{ _T("Menu") }}</span>
- </a>
- {% if login.isLogged() and (cur_route != 'mailing' and existing_mailing == true) %}
- <a
- id="recup_mailing"
- href="{{ url_for("mailing") }}"
- class="ui blue tooltip item"
- title="{{ _T("A mailing exists in the current session. Click here if you want to resume or cancel it.") }}"
- data-position="bottom right"
- >
- <i class="paper plane outline blue icon" aria-hidden="true"></i>
- <span class="displaynone">{{ _T("Existing mailing") }}</span>
- </a>
- {% endif %}
- <div class="header item">
- <img src="{{ url_for("logo") }}" width="{{ logo.getOptimalWidth() }}" height="{{ logo.getOptimalHeight() }}" alt="[ Galette ]" class="logo" />
- <span>{{ preferences.pref_nom }}</span>
- </div>
-
+ <a class="toc item" tabindex="0">
+ <i class="sidebar icon" aria-hidden="true"></i>
+ <span class="visually-hidden">{{ _T("Menu") }}</span>
+ </a>
+ <div class="header item">
+ <img src="{{ url_for("logo") }}" width="{{ logo.getOptimalWidth() }}" height="{{ logo.getOptimalHeight() }}" alt="[ Galette ]" class="logo" />
+ <span>{{ preferences.pref_nom }}</span>
+ </div>
+ <nav class="ui fluid container">
{% include "elements/navigation/public_pages.html.twig" with {
tips_position: "bottom center",
sign_in: true,
{% include "elements/modes.html.twig" %}
</div>
{% endif %}
- </div>
+ </nav>
</header>
} %}
</head>
<body id="galette_body" class="pushable dimmable{% if login.isLogged() %} loggedin{% endif %} nojs">
+ <a href="#main-content" class="skiptocontent visually-hidden focusable">{{ _T("Skip to content") }}</a>
{% include 'elements/navigation/navigation_sidebar.html.twig' %}
{% include 'elements/navigation/navigation_topbar.html.twig' %}
- <div class="pusher">
+ <main class="pusher">
<div id="main" class="{% if not login.isLogged() %}container{% else %} full height{% if i18n.isRtl() %} rtl{% endif %}{% endif %}">
{% if login.isLogged() %}
{% include 'elements/navigation/navigation_aside.html.twig' %}
<div class="sub header">{% if preferences.pref_slogan %}{{ __(preferences.pref_slogan) }}{% endif %}</div>
</div>
</div>
+ <a id="main-content" tabindex="-1"></a>
<h1 class="ui block center aligned header" style="position: relative">
{% else %}
<div class="ui horizontal basic segments header">
+ <div class="ui right aligned compact segment">
+ <nav class="ui compact tiny menu" aria-label="{{ _T('Language menu') }}">
+ {% include "elements/language.html.twig" with {
+ ui: "dropdown"
+ } %}
+ </nav>
+ </div>
+ <a id="main-content" tabindex="-1"></a>
<div class="ui center aligned segment">
<h1>
{% endif %}
</h1>
{% if login.isLogged() %}
</div>
- <div class="ui right aligned compact segment">
- <div class="ui compact tiny menu">
- {% if cur_route != 'mailing' and existing_mailing == true %}
- <a
- id="recup_mailing"
- href="{{ url_for("mailing") }}"
- class="ui blue tooltip item"
- title="{{ _T("A mailing exists in the current session. Click here if you want to resume or cancel it.") }}"
- data-position="bottom right"
- >
- <i class="paper plane outline blue icon" aria-hidden="true"></i>
- <span class="displaynone">{{ _T("Existing mailing") }}</span>
- </a>
- {% endif %}
- {% include "elements/language.html.twig" with {
- ui: "dropdown"
- } %}
- </div>
- </div>
</div>
{% endif %}
<div class="main-content">
{% include "elements/messages_inline.html.twig" %}
{% block content %}{{ _T('Page content') }}{% endblock %}
</div>
- {% include "elements/footer.html.twig" %}
</section>
</div>
- </div>
+ </main>
+ {% include "elements/footer.html.twig" %}
<a href="#" id="back2top" class="circular big ui icon button" title="{{ _T("Back to top") }}">
<i class="arrow up icon" aria-hidden="true"></i>
</a>
} %}
</head>
<body class="{% if body_class is defined and body_class == "front_page" %}front-page {% endif %}pushable{% if login.isLogged() %} loggedin{% endif %} nojs">
+ <a href="#main-content" class="skiptocontent visually-hidden focusable">{{ _T("Skip to content") }}</a>
{% include 'elements/navigation/navigation_sidebar.html.twig' %}
{% include 'elements/navigation/navigation_topbar.html.twig' %}
- <div class="pusher">
+ <main class="pusher">
<div id="main" class="{% if cur_route == "login" or cur_route == "password-lost" or cur_route == "password-recovery" or cur_route == "directlink" %}text {% endif %}{% if not login.isLogged() %}ui container{% else %}full height{% if i18n.isRtl() %} rtl{% endif %}{% endif %}">
{% if login.isLogged() %}
{% include "elements/navigation/navigation_aside.html.twig" %}
<div class="sub header">{% if preferences.pref_slogan %}{{ __(preferences.pref_slogan) }}{% endif %}</div>
</div>
</div>
+ <a id="main-content" tabindex="-1"></a>
<h1 class="ui block center aligned header" style="position: relative">
{% else %}
<div class="ui horizontal basic segments header">
+ <a id="main-content" tabindex="-1"></a>
<div class="ui center aligned segment">
<h1>
{% endif %}
{% include "elements/messages_inline.html.twig" %}
{% block content %}{{ _T("Public page content") }}{% endblock %}
</div>
- {% include "elements/footer.html.twig" %}
</section>
</div>
- </div>
+ </main>
+ {% include "elements/footer.html.twig" %}
<a href="#" id="back2top" class="circular big ui icon button" title="{{ _T("Back to top") }}">
<i class="arrow up icon" aria-hidden="true"></i>
</a>
<script type="text/javascript" src="./assets/js/jquery.min.js"></script>
</head>
<body class="pushable">
+ <a href="#main-content" class="skiptocontent visually-hidden focusable"><?php echo _T("Skip to content"); ?></a>
<header id="top-navbar" class="ui fixed menu bgcolor">
<div class="ui wide container">
<div class="header item">
</div>
</div>
</header>
- <div class="pusher">
- <div id="main" class="ui wide container">
+ <main class="pusher">
+ <section id="main" class="ui wide container">
<div class="ui basic segment">
<div class="ui basic center aligned fitted segment">
<img class="icon" alt="[ Galette ]" src="./themes/default/images/galette.png"/>
</div>
+ <a id="main-content" tabindex="-1"></a>
<h1 class="ui block center aligned header">
<?php echo $install->getStepTitle(); ?>
</h1>
</nav>
</div>
</footer>
- </div>
- </div>
+ </section>
+ </main>
<script type="text/javascript" src="./assets/js/galette-main.bundle.min.js"></script>
<script type="text/javascript" src="./themes/default/ui/semantic.min.js"></script>
</body>
/*---------------
Global
----------------*/
+/* Content using displaynone is ignored by screen readers */
.displaynone {
display: none !important;
}
+/* Content using visually-hidden is read by screen readers */
+.visually-hidden {
+ position: absolute !important;
+ width: 1px;
+ height: 1px;
+ clip: rect(1px,1px,1px,1px);
+ word-wrap: normal;
+ overflow: hidden;
+
+ &.focusable:active,
+ &.focusable:focus {
+ position: static !important;
+ width: auto;
+ height: auto;
+ clip: auto;
+ overflow: visible;
+ }
+}
+
.exemple,
.disabled,
.disabled a {
}
}
+/*---------------------------------
+ Go to main content link
+----------------------------------*/
+.skiptocontent {
+ display: block;
+ width: 100%;
+ text-decoration: none;
+ color: @invertedTextColor;
+ outline: 0;
+ background-color: @black;
+
+ &.focusable:hover,
+ &.focusable:focus {
+ position: absolute !important;
+ width: 100%;
+ z-index: 102;
+ padding: 1rem .5rem;
+ text-align: center;
+ outline: none;
+ }
+
+ &.focusable:hover {
+ color: @invertedTextColor;
+ text-decoration: underline;
+ }
+}
+
/*--------------------------------
Base layout and navigation
---------------------------------*/
flex-direction: column;
justify-content: center;
height: 100%;
+ padding-bottom: 120px;
img.logo {
margin-top: 1rem;
}
}
-body.pushable:not(.loggedin) > .pusher {
+body.pushable:not(.loggedin) {
+ & > .pusher {
display: flex;
justify-content: center;
+ padding-bottom: 120px;
+ }
+ main ~ footer.ui.segment {
+ margin-top: -120px;
+ z-index: 2;
+ }
}
.loggedin #main {
max-width: 100%;
}
+.loggedin .content {
+ .ui.horizontal.segments.header {
+ flex-direction: row-reverse;
+ }
+}
+
footer,
footer .ui.horizontal.list .list > .item,
footer .ui.horizontal.list > .item{
}
@media only screen and (max-width: 991px) {
- #top-navbar .item:not(.header):not(.toc):not(#recup_mailing) {
+ #top-navbar nav {
display: none;
}
.sidebar.uncover + .fixed.menu .toc i::before {
padding-top: 0;
}
+ #sidebarmenu {
+ display: none;
+ }
+ .ui.visible.left.sidebar ~ .pusher {
+ transform: translate3d(0, 0, 0) !important;
+ &.dimmed::after {
+ display: none;
+ }
+ }
#top-navbar div.item a.button.darkmode span {
display: none;
}
display: block;
}
+ html:not(.public_page) body:not(.front-page) main ~ footer.ui.segment,
body:not(.front-page) section.content {
margin-left: 260px;
flex: 1 1 auto;
width: 350px;
}
+ html:not(.public_page) body:not(.front-page) main ~ footer.ui.segment,
body:not(.front-page) section.content {
margin-left: 350px;
}