mirror of
https://github.com/dgtlmoon/changedetection.io.git
synced 2026-08-24 23:27:20 +00:00
sidebar fxies
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Build distribution 📦 (push) Has been cancelled
ChangeDetection.io App Test / lint-code (push) Has been cancelled
ChangeDetection.io App Test / lint-translations (push) Has been cancelled
ChangeDetection.io App Test / lint-template-i18n (push) Has been cancelled
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Test the built package works basically. (push) Has been cancelled
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Publish Python 🐍 distribution 📦 to PyPI (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-10 (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-11 (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-12 (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-13 (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-14 (push) Has been cancelled
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Build distribution 📦 (push) Has been cancelled
ChangeDetection.io App Test / lint-code (push) Has been cancelled
ChangeDetection.io App Test / lint-translations (push) Has been cancelled
ChangeDetection.io App Test / lint-template-i18n (push) Has been cancelled
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Test the built package works basically. (push) Has been cancelled
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Publish Python 🐍 distribution 📦 to PyPI (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-10 (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-11 (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-12 (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-13 (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-14 (push) Has been cancelled
This commit is contained in:
@@ -292,6 +292,10 @@ nav
|
||||
{{ render_field(form.application.form.ui.form.timeago_format) }}
|
||||
<span class="pure-form-message-inline">{{ _('How "Last Checked" and "Last Changed" times are shown in the watch overview list.') }}</span>
|
||||
</div>
|
||||
<div class="pure-control-group">
|
||||
{{ render_field(form.application.form.ui.form.sidebar_mode) }}
|
||||
<span class="pure-form-message-inline">{{ _('"Collapsed icon rail" keeps the left navigation slim and reveals labels on mouse-over; "Always expanded" keeps labels visible.') }}</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="tab-pane-inner" id="proxies">
|
||||
|
||||
@@ -196,6 +196,19 @@ def get_darkmode_state():
|
||||
def get_css_version():
|
||||
return __version__
|
||||
|
||||
@app.template_global()
|
||||
def get_sidebar_mode_class():
|
||||
"""Body class that drives the left-rail behaviour (see parts/_action_sidebar.scss).
|
||||
|
||||
'collapsed' -> slim icon rail that expands on hover/focus (actionsidebar-minimal)
|
||||
'pinned' -> rail always expanded with labels visible (actionside-bar-on)
|
||||
"""
|
||||
mode = datastore.data['settings']['application'].get('ui', {}).get('sidebar_mode', 'collapsed')
|
||||
# Pinned mode is permanently expanded, so it carries 'action-side-bar-expanded'
|
||||
# from the start. In collapsed mode that class is toggled on hover/focus by
|
||||
# static/js/sidebar.js.
|
||||
return 'actionside-bar-on action-side-bar-expanded' if mode == 'pinned' else 'actionsidebar-minimal'
|
||||
|
||||
@app.template_global()
|
||||
def get_socketio_path():
|
||||
"""Generate the correct Socket.IO path prefix for the client"""
|
||||
|
||||
@@ -1077,6 +1077,10 @@ class globalSettingsApplicationUIForm(Form):
|
||||
timeago_format = SelectField(_l('Relative time format'),
|
||||
choices=[('long', _l('Long (1 minute ago)')), ('short', _l('Short (1m ago)'))],
|
||||
default='long', validators=[validators.Optional()])
|
||||
sidebar_mode = SelectField(_l('Navigation sidebar'),
|
||||
choices=[('collapsed', _l('Collapsed icon rail (expands on hover)')),
|
||||
('pinned', _l('Always expanded'))],
|
||||
default='collapsed', validators=[validators.Optional()])
|
||||
|
||||
# datastore.data['settings']['application']..
|
||||
class globalSettingsApplicationForm(commonSettingsForm):
|
||||
|
||||
@@ -80,6 +80,7 @@ class model(dict):
|
||||
'socket_io_enabled': True,
|
||||
'favicons_enabled': True,
|
||||
'timeago_format': 'long', # 'long' = "1 minute ago", 'short' = "1m ago"
|
||||
'sidebar_mode': 'collapsed', # 'collapsed' = slim icon rail, expands on hover; 'pinned' = always expanded
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
//$action-sidebar-width-collapsed: 64px — used by the resting inner-block width and the content-main left-padding in minimal mode
|
||||
//$action-sidebar-content-slot: 1100px — editable content column; .content-main max-width is now derived as content_slot + collapsed_width
|
||||
|
||||
$action-sidebar-width-expanded: 190px;
|
||||
$action-sidebar-width-expanded: 200px;
|
||||
$action-sidebar-width-collapsed: 64px;
|
||||
$action-sidebar-content-slot: 1100px;
|
||||
|
||||
@@ -16,7 +16,16 @@ $action-sidebar-content-slot: 1100px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: $action-sidebar-width-expanded; // reserve enough to host the expanded inner block
|
||||
// Pin the rail to the viewport as a full-height column (like the demo's
|
||||
// `height: 100vh; position: sticky`). align-self:flex-start stops the flex
|
||||
// row from stretching it to the page-content height; sticky+100vh then keeps
|
||||
// it viewport-tall and fixed in place while the content scrolls, so the
|
||||
// footer list always rests at the bottom of the window.
|
||||
align-self: flex-start;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
height: 100vh;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
z-index: 60;
|
||||
pointer-events: none; // empty space doesn't intercept clicks/hovers
|
||||
@media only screen and (max-width: $desktop-wide-breakpoint) {
|
||||
@@ -25,6 +34,12 @@ $action-sidebar-content-slot: 1100px;
|
||||
}
|
||||
}
|
||||
|
||||
body.actionside-bar-on {
|
||||
.action-sidebar {
|
||||
/* width: $action-sidebar-width-expanded; // reserve enough to host the expanded inner block*/
|
||||
}
|
||||
}
|
||||
|
||||
// The actual interactive item block — wraps only the items, not the whole height.
|
||||
//
|
||||
// Two body-level modes drive the rail's display state:
|
||||
@@ -38,9 +53,17 @@ $action-sidebar-content-slot: 1100px;
|
||||
pointer-events: auto; // restore interactivity inside the block
|
||||
width: $action-sidebar-width-collapsed;
|
||||
overflow: hidden;
|
||||
// Fill the full height of the (stretched) rail and stack its lists in a
|
||||
// column, so the footer list can sit at the bottom (see --bottom below).
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
// Exit (mouse-away) is fast — snaps back to icons.
|
||||
transition: width 0.08s ease-out;
|
||||
|
||||
padding-left: $common-gap;
|
||||
padding-right: $common-gap;
|
||||
|
||||
// Hover-to-expand only fires in minimal mode.
|
||||
body.actionsidebar-minimal &:hover,
|
||||
body.actionsidebar-minimal &:focus-within {
|
||||
@@ -56,19 +79,24 @@ $action-sidebar-content-slot: 1100px;
|
||||
}
|
||||
}
|
||||
|
||||
.action-sidebar-list {
|
||||
ul.action-sidebar-list {
|
||||
list-style: none;
|
||||
padding-right: 0;
|
||||
padding-left: $common-gap/2;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
// Footer list (status counters, live spark, version) sits at the bottom of the
|
||||
// rail — the flex equivalent of the demo's `.rail-spacer { flex: 1 }`.
|
||||
.action-sidebar-list--bottom {
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
.action-sidebar-li {
|
||||
>:first-child {
|
||||
padding-left: $common-gap/2;
|
||||
/* padding-left: $common-gap/2;*/
|
||||
}
|
||||
|
||||
list-style: none;
|
||||
@@ -111,8 +139,9 @@ $action-sidebar-content-slot: 1100px;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 42px;
|
||||
/* width: 100%;*/
|
||||
/*height: 42px;*/
|
||||
padding: $common-gap;
|
||||
font-size: var(--body-main-text-size);
|
||||
border-radius: 8px;
|
||||
color: var(--color-white);
|
||||
@@ -259,7 +288,7 @@ body.actionside-bar-on {
|
||||
padding: 0.5rem 0.75rem;
|
||||
border-bottom: 1px solid var(--color-border-table-cell);
|
||||
|
||||
.action-sidebar-list {
|
||||
ul.action-sidebar-list {
|
||||
gap: 1px;
|
||||
}
|
||||
|
||||
@@ -365,4 +394,35 @@ body.actionside-bar-on {
|
||||
.mobile-menu-section .action-sidebar-item {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** top logo stuff */
|
||||
#action-sidebar-logo {
|
||||
padding: $common-gap;
|
||||
}
|
||||
|
||||
.actionsidebar-minimal {
|
||||
#cdio-logo {
|
||||
#logo-expanded {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.action-side-bar-expanded {
|
||||
#cdio-logo {
|
||||
#logo-expanded {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.action-side-bar-expanded {
|
||||
#cdio-logo {
|
||||
#logo-short {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,9 +72,31 @@ body {
|
||||
// column side-by-side on desktop, stacked on mobile. Not sidebar-specific — the
|
||||
// rail's parts/_action_sidebar.scss styles target the rail itself, this is the
|
||||
// outer wrapper any future side-column layout could share.
|
||||
// App shell — the demo's `.app`: a full-height flex row whose left column is the
|
||||
// navigation rail and whose right column (`.app-main`) stacks the top menu over
|
||||
// the page content. `min-height: 100vh` guarantees the rail's gutter runs the
|
||||
// full window height even when the page content is short.
|
||||
.app {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
min-height: 100vh;
|
||||
// No gap here on purpose: the top menu (.header) should sit flush against the
|
||||
// rail. The content's breathing room from the rail is applied to
|
||||
// section.content alone (padding-left below), not the whole right column.
|
||||
}
|
||||
|
||||
// Right-hand column: top menu (.header) above the scrolling content.
|
||||
.app-main {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
// Space between the top menu and the page content below it.
|
||||
gap: $common-gap;
|
||||
}
|
||||
|
||||
.content-wrapper {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
position: relative;
|
||||
@@ -98,7 +120,7 @@ body {
|
||||
align-items: center;
|
||||
@media only screen and (min-width: $desktop-wide-breakpoint) {
|
||||
flex-direction: column;
|
||||
padding-right: 1rem;
|
||||
padding-top: 4rem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,9 +212,10 @@ body.spinner-active {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
}
|
||||
.pure-menu-heading {
|
||||
color: var(--color-text-menu-heading);
|
||||
padding-left: $common-gap;
|
||||
|
||||
#cdio-logo {
|
||||
color: var(--color-white);
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.pure-menu-link {
|
||||
@@ -211,13 +234,17 @@ body.spinner-active {
|
||||
}
|
||||
|
||||
section.content {
|
||||
padding-top: 80px;
|
||||
|
||||
// The top menu (.header) now sits in-flow above this section inside .app-main,
|
||||
// so the old fixed-header clearance (padding-top: 80px) is no longer needed.
|
||||
// Inset the content from the rail (and the window's right edge) so it doesn't
|
||||
// butt against the left action bar — the header above stays flush to the rail.
|
||||
padding-bottom: 1em;
|
||||
padding-left: $common-gap;
|
||||
padding-right: $common-gap;
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
code {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -52,19 +52,20 @@
|
||||
{%- endif %}
|
||||
</head>
|
||||
|
||||
<body class="actionside-bar-on {{extra_classes}}">
|
||||
<body class="{{ get_sidebar_mode_class() }} {{extra_classes}}">
|
||||
<div class="app">
|
||||
{% if current_user.is_authenticated or not has_password %}
|
||||
<aside class="action-sidebar" aria-label="{{ _('Main navigation') }}">
|
||||
<div class="action-sidebar-inner">
|
||||
{% include "sidebar-nav.html" %}
|
||||
</div>
|
||||
</aside>
|
||||
{% endif %}
|
||||
<div class="app-main">
|
||||
<div class="header">
|
||||
<div {% if pure_menu_fixed != False %}class="pure-menu-fixed"{% endif %} style="width: 100%;">
|
||||
<div>
|
||||
<div class="home-menu pure-menu pure-menu-horizontal" id="nav-menu">
|
||||
|
||||
{% if has_password and not current_user.is_authenticated %}
|
||||
<a id="cdio-logo" class="pure-menu-heading" href="https://changedetection.io" rel="noopener">
|
||||
<strong>Change</strong>Detection.io</a>
|
||||
{% else %}
|
||||
<a id="cdio-logo" class="pure-menu-heading" href="{{url_for('watchlist.index')}}">
|
||||
<strong>Change</strong>Detection.io</a>
|
||||
{% endif %}
|
||||
{% if current_diff_url and is_safe_valid_url(current_diff_url) %}
|
||||
{% if current_diff_url and is_safe_valid_url(current_diff_url) %}
|
||||
<a class="current-diff-url" href="{{ current_diff_url }}" title="{{ current_diff_url }}">
|
||||
<span>{{ current_diff_url }}</span></a>
|
||||
{% endif %}
|
||||
@@ -170,13 +171,6 @@
|
||||
</div>
|
||||
|
||||
<div class="content-wrapper">
|
||||
{% if current_user.is_authenticated or not has_password %}
|
||||
<aside class="action-sidebar" aria-label="{{ _('Main navigation') }}">
|
||||
<div class="action-sidebar-inner">
|
||||
{% include "sidebar-nav.html" %}
|
||||
</div>
|
||||
</aside>
|
||||
{% endif %}
|
||||
<div class="content-main">
|
||||
|
||||
{% if header %}
|
||||
@@ -204,8 +198,11 @@
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div><!-- /.app-main -->
|
||||
</div><!-- /.app -->
|
||||
<script src="{{url_for('static_content', group='js', filename='toggle-theme.js')}}" defer></script>
|
||||
<script src="{{url_for('static_content', group='js', filename='hamburger-menu.js')}}" defer></script>
|
||||
<script src="{{url_for('static_content', group='js', filename='sidebar.js')}}" defer></script>
|
||||
|
||||
<div id="checking-now-fixed-tab" style="display: none;"><span class="spinner"></span><span class="status-text"> {{ _('Checking now') }}</span></div>
|
||||
<div id="realtime-conn-error" style="display:none">{{ _('Real-time updates offline') }}</div>
|
||||
|
||||
@@ -2,7 +2,22 @@
|
||||
{# Used by base.html (desktop left sidebar) and mobile hamburger drawer #}
|
||||
|
||||
{%- set ep = request.endpoint or '' -%}
|
||||
<ul class="action-sidebar-list">
|
||||
|
||||
<ul class="action-sidebar-list action-sidebar-list--top">
|
||||
<li class="action-sidebar-li" id="action-sidebar-logo">
|
||||
|
||||
{%- if has_password and not current_user.is_authenticated -%}
|
||||
<a id="cdio-logo" href="https://changedetection.io" rel="noopener">
|
||||
<span id="logo-expanded"><strong>Change</strong>Detection.io</span>
|
||||
<span id="logo-short"><strong>CD</strong>IO</span>
|
||||
</a>
|
||||
{%- else -%}
|
||||
<a id="cdio-logo" href="{{url_for('watchlist.index')}}">
|
||||
<span id="logo-expanded"><strong>Change</strong>Detection.io</span>
|
||||
<span id="logo-short"><strong>CD</strong>IO</span>
|
||||
</a>
|
||||
{%- endif -%}
|
||||
</li>
|
||||
<li class="action-sidebar-li">
|
||||
<a href="{{ url_for('add_watch_ui.add_watch_ui_index') }}"
|
||||
class="action-sidebar-item {% if ep.startswith('add_watch_ui.') %}active{% endif %}"
|
||||
@@ -92,7 +107,12 @@
|
||||
<span class="action-label">{{ _('Notifications') }}</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
{# Footer group — pushed to the bottom of the rail via `margin-top: auto`
|
||||
(see .action-sidebar-list--bottom). Mirrors the demo's bottom-aligned rail
|
||||
footer (status counters, live spark, version). #}
|
||||
<ul class="action-sidebar-list action-sidebar-list--bottom">
|
||||
<li class="action-sidebar-divider" aria-hidden="true"></li>
|
||||
|
||||
<li class="action-sidebar-li" id="checking-now-stats-sidebar">
|
||||
|
||||
Reference in New Issue
Block a user