diff --git a/nipap-www/nipapwww/static/css/nipap.css b/nipap-www/nipapwww/static/css/nipap.css index ce3a943a8..6d2a894b8 100644 --- a/nipap-www/nipapwww/static/css/nipap.css +++ b/nipap-www/nipapwww/static/css/nipap.css @@ -1009,3 +1009,23 @@ tbody.listing > tr:hover { /* * $("#length_info_row").animate({ backgroundColor: "#ffffff" }, 1).delay(200).animate({ backgroundColor: "#dddd33" }, 300).delay(200).animate({ backgroundColor: "#ffffee" }, 1000); */ + +#floating_prefix_header { + background-color: #FFFFFF; +} + +.login-result { + padding: 15px; +} + +.login-result-error { + background-color: #ffcccc; + color: #651b1b; +} + +.login-result-success, +.result-success { + padding: 15px; + background-color: #ccffcc; + color: #17452b; +} diff --git a/nipap-www/nipapwww/static/css/theme.css b/nipap-www/nipapwww/static/css/theme.css new file mode 100644 index 000000000..35df9d596 --- /dev/null +++ b/nipap-www/nipapwww/static/css/theme.css @@ -0,0 +1,178 @@ +:root { + color-scheme: light; +} + +.theme-switch-label { + margin: 0 8px 0 0; + color: #ccc; + vertical-align: middle; + cursor: pointer; +} + +#theme-switch { + display: inline-block; + position: relative; + width: 44px; + height: 24px; + padding: 0; + border: 1px solid #8793a4; + border-radius: 14px; + background: #566171; + vertical-align: middle; + cursor: pointer; + touch-action: none; +} + +#theme-switch[aria-checked="true"] { + background: #2868c5; + border-color: #93c5fd; +} + +.theme-switch-thumb { + position: absolute; + top: 2px; + left: 2px; + width: 18px; + height: 18px; + border-radius: 50%; + background: #fff; + pointer-events: none; + transition: transform 120ms ease; +} + +#theme-switch[aria-checked="true"] .theme-switch-thumb { + transform: translateX(20px); +} + +#theme-switch:focus-visible { + outline: 2px solid #93c5fd; + outline-offset: 3px; +} + +@media (prefers-reduced-motion: reduce) { + .theme-switch-thumb { transition: none; } +} + +:root[data-theme="dark"] { + color-scheme: dark; + --theme-bg: #151a22; + --theme-panel: #202835; + --theme-hover: #2c394b; + --theme-text: #e3e9f2; + --theme-muted: #adb9cb; + --theme-border: #48556a; + background: var(--theme-bg); +} + +[data-theme="dark"] body { + background: var(--theme-bg); + color: var(--theme-text); +} + +[data-theme="dark"] a { color: #93c5fd; } +[data-theme="dark"] a:hover { color: #c5dfff; } + +[data-theme="dark"] .dropdown-menu > li > a { + color: var(--theme-text); +} + +[data-theme="dark"] .dropdown-menu > li > a:is(:hover, :focus), +[data-theme="dark"] .dropdown-menu > .active > a, +[data-theme="dark"] .dropdown-menu > .active > a:is(:hover, :focus) { + background: var(--theme-hover); + color: var(--theme-text); +} + +[data-theme="dark"] .dropdown-menu > .disabled > a, +[data-theme="dark"] .dropdown-menu > .disabled > a:is(:hover, :focus) { + background: transparent; + color: var(--theme-muted); +} + +[data-theme="dark"] :is(.options-group, .options-content, .options-group-heading, + .options-guide, .page-title, #search_box, .popup_menu, .selector, .prefix_select_container, + .selector_filterbar, .ui-widget-content, .ui-widget-header, .ui-dialog, + .ui-dialog-question, .modal-content, .panel, .panel-heading, .well, + .dropdown-menu, .table-striped > tbody > tr:nth-of-type(odd), pre, + .minibutton, .vrf_filter_entry_rt, .preflist_vrf_rt) { + background: var(--theme-panel); + color: var(--theme-text); + border-color: var(--theme-border); + text-shadow: none; +} + +[data-theme="dark"] :is(input:not([type="submit"]):not([type="button"]), + textarea, select, .form-control, .btn-default, + ul.tagit, tags-input .tags, .ui-state-default) { + background: var(--theme-bg); + color: var(--theme-text); + border-color: var(--theme-border); +} + +[data-theme="dark"] :is(input, textarea)::placeholder { color: var(--theme-muted); } +[data-theme="dark"] :is(.row_match, .selector_entry_name, .selector > div > a, .popup_menu > a) { + color: var(--theme-text); +} +[data-theme="dark"] :is(.row_collateral, .prefix_hidden_text, .prefix_vrf, .version > a, .text-muted) { + color: var(--theme-muted); +} +[data-theme="dark"] :is(.option:hover, .prefix_entry:hover, tbody.listing > tr:hover, + .dropdown-menu > li > a:hover, .minibutton:hover) { + background: var(--theme-hover); +} +[data-theme="dark"] :is(.table > tbody > tr > td, + .table > thead > tr > th, .rule, hr, .top_menu) { + border-color: var(--theme-border); +} +[data-theme="dark"] :is(.required, .text-danger) { color: #ff9c9c; } +[data-theme="dark"] .prefix_added_entry { background: #204535; color: #d6f5e1; } +[data-theme="dark"] .login-result-error { background: #4a2428; color: #ffd6d6; } +[data-theme="dark"] .login-result-success, +[data-theme="dark"] .result-success { background: #204535; color: #d6f5e1; } +[data-theme="dark"] .popup_menu h3 { background: var(--theme-panel); text-shadow: none; } + +[data-theme="dark"] #query_string { + background: var(--theme-bg); + color: var(--theme-text); + border-color: var(--theme-border); +} + +[data-theme="dark"] #query_string:focus { + border-color: #93c5fd; +} + +[data-theme="dark"] #floating_prefix_header { + background-color: var(--theme-panel); + border-color: var(--theme-border); +} + +[data-theme="dark"] .preflist_vrf_panel { + color: var(--theme-muted); + border-color: var(--theme-border); +} + +[data-theme="dark"] .prefix_list_header { + background: var(--theme-panel); + color: var(--theme-text); + border-color: var(--theme-border); +} + +/* Keep action links readable instead of inheriting the normal link color. */ +[data-theme="dark"] .btn.btn-success { + background: #286c38; + color: #fff; + border-color: #5cb85c; + text-shadow: none; +} + +[data-theme="dark"] .btn.btn-success:is(:hover, :focus, :active, .active), +[data-theme="dark"] .open > .btn.btn-success.dropdown-toggle { + background: #20582e; + color: #fff; + border-color: #5cb85c; +} + +[data-theme="dark"] .btn.btn-success:focus-visible { + outline: 2px solid #93c5fd; + outline-offset: 3px; +} diff --git a/nipap-www/nipapwww/static/templates/pool_add.html b/nipap-www/nipapwww/static/templates/pool_add.html index 5153350c6..d2d66bbc3 100644 --- a/nipap-www/nipapwww/static/templates/pool_add.html +++ b/nipap-www/nipapwww/static/templates/pool_add.html @@ -8,7 +8,7 @@

Result

-
+
The pool {{ pool.name }} was successfully added.
diff --git a/nipap-www/nipapwww/static/templates/pool_edit.html b/nipap-www/nipapwww/static/templates/pool_edit.html index 975df6639..acfbf9e79 100644 --- a/nipap-www/nipapwww/static/templates/pool_edit.html +++ b/nipap-www/nipapwww/static/templates/pool_edit.html @@ -8,7 +8,7 @@

Result

-
+
The pool {{ pool.name }} was successfully edited.
diff --git a/nipap-www/nipapwww/static/templates/prefix_edit.html b/nipap-www/nipapwww/static/templates/prefix_edit.html index 0c0baee91..413eb21df 100644 --- a/nipap-www/nipapwww/static/templates/prefix_edit.html +++ b/nipap-www/nipapwww/static/templates/prefix_edit.html @@ -8,7 +8,7 @@

Result

-
+
The prefix {{ prefix.prefix }} was successfully edited.
diff --git a/nipap-www/nipapwww/static/templates/vrf_add.html b/nipap-www/nipapwww/static/templates/vrf_add.html index d487bee3a..1a8b595fd 100644 --- a/nipap-www/nipapwww/static/templates/vrf_add.html +++ b/nipap-www/nipapwww/static/templates/vrf_add.html @@ -8,7 +8,7 @@

Result

-
+
The VRF {{ vrf.rt }} was successfully added.
diff --git a/nipap-www/nipapwww/static/templates/vrf_edit.html b/nipap-www/nipapwww/static/templates/vrf_edit.html index 305194ecd..1759a3401 100644 --- a/nipap-www/nipapwww/static/templates/vrf_edit.html +++ b/nipap-www/nipapwww/static/templates/vrf_edit.html @@ -8,7 +8,7 @@

Result

-
+
The VRF {{ vrf.rt }} was successfully edited.
diff --git a/nipap-www/nipapwww/static/theme.js b/nipap-www/nipapwww/static/theme.js new file mode 100644 index 000000000..69522c62d --- /dev/null +++ b/nipap-www/nipapwww/static/theme.js @@ -0,0 +1,77 @@ +(function () { + 'use strict'; + var preference; + var systemTheme = window.matchMedia('(prefers-color-scheme: dark)'); + try { + preference = localStorage.getItem('nipap-theme'); + } catch (error) { + // The switch still works when browser storage is unavailable. + } + if (preference !== 'dark' && preference !== 'light') { + preference = null; + } + + function applyTheme() { + var dark = preference ? preference === 'dark' : systemTheme.matches; + document.documentElement.dataset.theme = dark ? 'dark' : 'light'; + var control = document.getElementById('theme-switch'); + if (control) { + control.setAttribute('aria-checked', String(dark)); + } + } + + applyTheme(); + systemTheme.addEventListener('change', applyTheme); + document.addEventListener('DOMContentLoaded', function () { + var control = document.getElementById('theme-switch'); + var startX = null; + var dragged = false; + function select(dark) { + preference = dark ? 'dark' : 'light'; + try { + localStorage.setItem('nipap-theme', preference); + } catch (error) { + // Retain the selection for this page even without storage. + } + applyTheme(); + } + applyTheme(); + control.addEventListener('click', function () { + if (dragged) { + dragged = false; + return; + } + select(document.documentElement.dataset.theme !== 'dark'); + }); + control.addEventListener('pointerdown', function (event) { + if (!event.isPrimary || event.button !== 0) { + return; + } + startX = event.clientX; + dragged = false; + control.setPointerCapture(event.pointerId); + }); + control.addEventListener('pointerup', function (event) { + if (startX === null) { + return; + } + var distance = event.clientX - startX; + startX = null; + if (Math.abs(distance) > 8) { + dragged = true; + select(distance > 0); + } + }); + control.addEventListener('pointercancel', function () { + startX = null; + dragged = false; + }); + control.addEventListener('keydown', function (event) { + dragged = false; + if (event.key === 'ArrowLeft' || event.key === 'ArrowRight') { + event.preventDefault(); + select(event.key === 'ArrowRight'); + } + }); + }); +}()); diff --git a/nipap-www/nipapwww/templates/base.html b/nipap-www/nipapwww/templates/base.html index 49d3a3477..1f1f377d0 100644 --- a/nipap-www/nipapwww/templates/base.html +++ b/nipap-www/nipapwww/templates/base.html @@ -4,6 +4,7 @@ {{ g.page_title|default('NIPAP') }} + @@ -64,6 +65,7 @@ ng_compile = angular.element($('html')).injector().get('$compile'); }); + {% block head %} {% endblock %} @@ -95,6 +97,12 @@
    +
  1. + + +
  2. Log out
  3. diff --git a/nipap-www/nipapwww/templates/login.html b/nipap-www/nipapwww/templates/login.html index 30ac36f1b..9b4abb21a 100644 --- a/nipap-www/nipapwww/templates/login.html +++ b/nipap-www/nipapwww/templates/login.html @@ -49,7 +49,7 @@

    Result

    -
    +
    @@ -62,7 +62,7 @@

    Result

    Result

    -
    +
    diff --git a/nipap-www/nipapwww/templates/macros.html b/nipap-www/nipapwww/templates/macros.html index efb6479ca..ecfa016df 100644 --- a/nipap-www/nipapwww/templates/macros.html +++ b/nipap-www/nipapwww/templates/macros.html @@ -56,7 +56,7 @@
    Description
    -