Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
2a2078e
rework the top navbar menu with compliance as starting point
tdruez Apr 24, 2026
aa24c80
add side_menu navigation
tdruez Apr 24, 2026
a124a80
refine side_menu navigation
tdruez Apr 24, 2026
a4bb068
adjust CSS
tdruez Apr 24, 2026
d54ab94
refine the menu button
tdruez Apr 24, 2026
08928f8
move external links to right nav menu
tdruez Apr 27, 2026
7e40a4a
move CSS to main file
tdruez Apr 27, 2026
c77cf60
remove dropdown from nav-brand
tdruez Apr 27, 2026
1bb8832
rework the search into a modal
tdruez Apr 27, 2026
22743e1
display as rounded pills
tdruez Apr 27, 2026
62d94d8
display the search modal from the top
tdruez Apr 27, 2026
a6560da
refine the rendering of the search button in nav
tdruez Apr 27, 2026
118dce7
adjust margin
tdruez Apr 27, 2026
1bbc70a
adjust main dejacode button rendering
tdruez Apr 27, 2026
1b84a00
add focus and hover behavior to the navbar buttons
tdruez Apr 27, 2026
c38ac3c
add text-warning to the icon
tdruez Apr 27, 2026
9bece62
add missing global search URL
tdruez Apr 28, 2026
adab562
remove the SHOW_TOOLS_IN_NAV setting
tdruez Apr 28, 2026
09d42ae
remove the SHOW_TOOLS_IN_NAV setting
tdruez Apr 28, 2026
9142e86
adjust the break points
tdruez Apr 28, 2026
ffbb9fc
adjust the break points
tdruez Apr 28, 2026
bdb2daf
set offcanva size
tdruez Apr 28, 2026
fc15fab
adjust label color and rendering for consistency in compliance tab
tdruez Apr 28, 2026
1741846
revert the background color for the offcanva menu
tdruez Apr 28, 2026
e3d3954
reflect the active theme in the dropdown
tdruez Apr 29, 2026
676e148
fix the focus order
tdruez Apr 29, 2026
45addd8
add Requests in navbar header when viewpoint is large enough
tdruez Apr 29, 2026
cee2f62
fix rendering of the offcanvas button
tdruez Apr 29, 2026
320419d
fix rendering of the offcanvas button
tdruez Apr 29, 2026
ee113fb
fix the anonymous rendering
tdruez Apr 29, 2026
7df0c1b
update URL to aboutcode
tdruez Apr 29, 2026
fbbe55c
add ability to hide external links with SHOW_MENU_EXTERNAL_LINKS
tdruez Apr 29, 2026
2c5333e
fix the buttons color to white
tdruez Apr 29, 2026
60c4931
bring back nav item separators
tdruez Apr 29, 2026
133452f
fix rendering of left menu in rest api view
tdruez Apr 29, 2026
664d97d
fix failing unit tests
tdruez Apr 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 1 addition & 7 deletions dejacode/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ def gettext_noop(s):
SITE_TITLE = env.str("SITE_TITLE", default="DejaCode")
HEADER_TEMPLATE = env.str("HEADER_TEMPLATE", default="includes/header.html")
FOOTER_TEMPLATE = env.str("FOOTER_TEMPLATE", default="includes/footer.html")
SHOW_MENU_EXTERNAL_LINKS = env.bool("SHOW_MENU_EXTERNAL_LINKS", default=True)

GRAPPELLI_INDEX_DASHBOARD = "dje.dashboard.DejaCodeDashboard"
GRAPPELLI_CLEAN_INPUT_TYPES = False
Expand All @@ -377,13 +378,6 @@ def gettext_noop(s):
# An email address displayed in UI for users to reach the support team.
DEJACODE_SUPPORT_EMAIL = env.str("DEJACODE_SUPPORT_EMAIL", default="")

# Enable this setting to display a "Tools" section in the navbar including
# links to the "Requests" and "Reporting" views.
SHOW_TOOLS_IN_NAV = env.bool("SHOW_TOOLS_IN_NAV", default=True)

# Set False to hide the "Product Portfolio" section in the navbar.
SHOW_PP_IN_NAV = env.bool("SHOW_PP_IN_NAV", default=True)

# An integer specifying how many objects should be displayed per table whithin tabs.
TAB_PAGINATE_BY = env.int("TAB_PAGINATE_BY", default=100)

Expand Down
30 changes: 23 additions & 7 deletions dejacode/static/css/dejacode_bootstrap.css
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,6 @@ table.text-break thead {
background-color: var(--bs-djc-blue-bg);
height: 54px;
}
.navbar .offcanvas {
background-color: var(--bs-djc-blue-bg) !important;
}
.navbar-nav .active>.nav-link,
.navbar-nav .show>.nav-link
.navbar-nav .nav-link.active,
Expand All @@ -153,11 +150,30 @@ table.text-break thead {
text-underline-position: under;
color: var(--bs-white);
}
.navbar #search-input::placeholder {
color: var(--bs-gray-300);
.navbar .offcanvas {
background-color: var(--bs-djc-blue-bg) !important;
}
.navbar #search-form {
width: 350px;
.offcanvas {
--bs-offcanvas-width: 280px;
}
.nav-chip {
transition: background-color 0.15s ease, border-color 0.15s ease;
}
.nav-chip:hover,
.nav-chip:focus-visible {
background-color: rgba(255, 255, 255, 0.18) !important;
border-color: rgba(255, 255, 255, 0.5) !important;
}

/* -- Side menu -- */
#side-menu .nav-pills .nav-link.active {
color: #fff !important;
}
#side-menu .nav-link {
text-decoration: none;
}
#side-menu .nav-pills .nav-link:not(.active):hover {
background-color: var(--bs-tertiary-bg);
}

/* -- Pagination -- */
Expand Down
115 changes: 57 additions & 58 deletions dejacode/static/js/bootstrap_theme_toggler.js
Original file line number Diff line number Diff line change
@@ -1,81 +1,80 @@
/*!
* Color mode toggler for Bootstrap's docs (https://getbootstrap.com/)
* Copyright 2011-2023 The Bootstrap Authors
* Licensed under the Creative Commons Attribution 3.0 Unported License.
* https://getbootstrap.com/docs/5.3/customize/color-modes/#javascript
*/
* Color mode toggler for Bootstrap's docs (https://getbootstrap.com/)
* Copyright 2011-2025 The Bootstrap Authors
* Licensed under the Creative Commons Attribution 3.0 Unported License.
*/

(() => {
'use strict'
'use strict'

const getStoredTheme = () => localStorage.getItem('theme')
const setStoredTheme = theme => localStorage.setItem('theme', theme)

const getPreferredTheme = () => {
const storedTheme = getStoredTheme()
if (storedTheme) {
return storedTheme
}
const getPreferredTheme = () => {
const storedTheme = getStoredTheme()
if (storedTheme) {
return storedTheme
}

return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
}
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
}

const setTheme = theme => {
if (theme === 'auto' && window.matchMedia('(prefers-color-scheme: dark)').matches) {
document.documentElement.setAttribute('data-bs-theme', 'dark')
} else {
document.documentElement.setAttribute('data-bs-theme', theme)
const setTheme = theme => {
if (theme === 'auto') {
document.documentElement.setAttribute('data-bs-theme', (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'))
} else {
document.documentElement.setAttribute('data-bs-theme', theme)
}
}
}

setTheme(getPreferredTheme())
setTheme(getPreferredTheme())

const showActiveTheme = (theme, focus = false) => {
const themeSwitcher = document.querySelector('#bd-theme')
const showActiveTheme = (theme, focus = false) => {
const themeSwitcher = document.querySelector('#bd-theme')

if (!themeSwitcher) {
return
}
if (!themeSwitcher) {
return
}

const themeSwitcherText = document.querySelector('#bd-theme-text')
const activeThemeIcon = document.querySelector('.theme-icon-active use')
const btnToActive = document.querySelector(`[data-bs-theme-value="${theme}"]`)
const svgOfActiveBtn = btnToActive.querySelector('svg use').getAttribute('href')
const themeSwitcherText = document.querySelector('#bd-theme-text')
const activeThemeIcon = document.querySelector('.theme-icon-active use')
const btnToActive = document.querySelector(`[data-bs-theme-value="${theme}"]`)
const svgOfActiveBtn = btnToActive.querySelector('svg use').getAttribute('href')

document.querySelectorAll('[data-bs-theme-value]').forEach(element => {
element.classList.remove('active')
element.setAttribute('aria-pressed', 'false')
})
document.querySelectorAll('[data-bs-theme-value]').forEach(element => {
element.classList.remove('active')
element.setAttribute('aria-pressed', 'false')
})

btnToActive.classList.add('active')
btnToActive.setAttribute('aria-pressed', 'true')
activeThemeIcon.setAttribute('href', svgOfActiveBtn)
const themeSwitcherLabel = `${themeSwitcherText.textContent} (${btnToActive.dataset.bsThemeValue})`
themeSwitcher.setAttribute('aria-label', themeSwitcherLabel)
btnToActive.classList.add('active')
btnToActive.setAttribute('aria-pressed', 'true')
activeThemeIcon.setAttribute('href', svgOfActiveBtn)
const themeSwitcherLabel = `${themeSwitcherText.textContent} (${btnToActive.dataset.bsThemeValue})`
themeSwitcher.setAttribute('aria-label', themeSwitcherLabel)

if (focus) {
themeSwitcher.focus()
if (focus) {
themeSwitcher.focus()
}
}
}

window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
const storedTheme = getStoredTheme()
if (storedTheme !== 'light' && storedTheme !== 'dark') {
setTheme(getPreferredTheme())
}
})
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
const storedTheme = getStoredTheme()
if (storedTheme !== 'light' && storedTheme !== 'dark') {
setTheme(getPreferredTheme())
}
})

window.addEventListener('DOMContentLoaded', () => {
showActiveTheme(getPreferredTheme())
window.addEventListener('DOMContentLoaded', () => {
showActiveTheme(getPreferredTheme())

document.querySelectorAll('[data-bs-theme-value]')
.forEach(toggle => {
toggle.addEventListener('click', () => {
const theme = toggle.getAttribute('data-bs-theme-value')
setStoredTheme(theme)
setTheme(theme)
showActiveTheme(theme, true)
document.querySelectorAll('[data-bs-theme-value]')
.forEach(toggle => {
toggle.addEventListener('click', () => {
const theme = toggle.getAttribute('data-bs-theme-value')
setStoredTheme(theme)
setTheme(theme)
showActiveTheme(theme, true)
})
})
})
})
})
})()
77 changes: 69 additions & 8 deletions dejacode/static/js/dejacode_main.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,73 @@ function setupHTMX() {
});
}

function setupSearchModal() {
const searchForm = document.getElementById('search-form');
const searchInput = document.getElementById('search-input');
const searchModal = document.getElementById('search-modal');

if (!searchModal) return;

// Scope selector buttons
if (searchForm) {
document.querySelectorAll('.search-scope-btn').forEach(button => {
button.addEventListener('click', () => {
document.querySelectorAll('.search-scope-btn').forEach(b => b.classList.remove('active'));
button.classList.add('active');
searchForm.setAttribute('action', button.dataset.scopeAction);
searchInput.focus();
});
});
}

// Autofocus input when modal opens
searchModal.addEventListener('shown.bs.modal', () => {
searchInput.focus();
searchInput.select();
});

// Move focus out before aria-hidden is restored to avoid accessibility warning
searchModal.addEventListener('hide.bs.modal', () => {
if (document.activeElement) document.activeElement.blur();
});

// Keyboard shortcuts: Ctrl/Cmd+K and / to open the modal
document.addEventListener('keydown', (event) => {
const isTyping = ['INPUT', 'TEXTAREA', 'SELECT'].includes(document.activeElement.tagName) || document.activeElement.isContentEditable;
const modalInstance = bootstrap.Modal.getOrCreateInstance(searchModal);

if ((event.ctrlKey || event.metaKey) && event.key === 'k') {
event.preventDefault();
modalInstance.show();
} else if (event.key === '/' && !isTyping) {
event.preventDefault();
modalInstance.show();
}
});
}

function setupThemeSwitcher() {
// Reflects the active theme on the dropdown buttons since Bootstrap's own
// script targets its docs-specific markup and skips ours.
const getActiveTheme = () => localStorage.getItem('theme') || 'auto';

const markActiveTheme = theme => {
document.querySelectorAll('[data-bs-theme-value]').forEach(btn => {
const isActive = btn.getAttribute('data-bs-theme-value') === theme;
btn.classList.toggle('active', isActive);
btn.setAttribute('aria-pressed', isActive);
});
};

markActiveTheme(getActiveTheme());

document.querySelectorAll('[data-bs-theme-value]').forEach(btn => {
btn.addEventListener('click', () => {
markActiveTheme(btn.getAttribute('data-bs-theme-value'));
});
});
}

document.addEventListener('DOMContentLoaded', () => {
NEXB = {};
NEXB.client_data = JSON.parse(document.getElementById("client_data").textContent);
Expand Down Expand Up @@ -157,17 +224,11 @@ document.addEventListener('DOMContentLoaded', () => {
document.body.appendChild(overlay);
}

// Search selection in the header
$('#search-selector-list a').click(function(event) {
event.preventDefault();
$('#search-form').attr('action', $(this).attr('href'));
$('#search-selector-content').html($(this).html());
$('#search-input').focus();
});

setupTooltips();
setupPopovers();
setupSelectionCheckboxes();
setupBackToTop();
setupHTMX();
setupSearchModal();
setupThemeSwitcher();
});
3 changes: 1 addition & 2 deletions dje/context_processors.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ def dejacode_context(request):
"SITE_TITLE": settings.SITE_TITLE,
"HEADER_TEMPLATE": settings.HEADER_TEMPLATE,
"FOOTER_TEMPLATE": settings.FOOTER_TEMPLATE,
"SHOW_PP_IN_NAV": settings.SHOW_PP_IN_NAV,
"SHOW_TOOLS_IN_NAV": settings.SHOW_TOOLS_IN_NAV,
"SHOW_MENU_EXTERNAL_LINKS": settings.SHOW_MENU_EXTERNAL_LINKS,
"AXES_ENABLED": settings.AXES_ENABLED,
"LOGIN_FORM_ALERT": settings.LOGIN_FORM_ALERT,
}
3 changes: 3 additions & 0 deletions dje/templates/bootstrap_base.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
{% if FAVICON_HREF %}<link rel="icon" href="{{ FAVICON_HREF }}">{% endif %}
</head>
<body class="d-flex flex-column h-100 {% block bodyclass %}{% endblock %}">
{% block side_menu %}
{% include 'navbar/side_menu.html' %}
{% endblock %}
<header>
{% block header %}
{% include HEADER_TEMPLATE %}
Expand Down
4 changes: 2 additions & 2 deletions dje/templates/includes/footer.html
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{% load i18n %}
<footer class="footer mt-auto bg-body-tertiary text-body-secondary">
<footer class="footer mt-auto bg-body-tertiary">
<div class="container-fluid p-3 p-md-5">
<ul class="list-unstyled">
<li><a href="/">Home</a></li>{# No trans for Home on purpose #}
<li><a href="https://dejacode.readthedocs.io/en/latest/" target="_blank" rel="noreferrer">{% trans 'Documentation' %}</a></li>
<li><a href="https://www.nexb.com/resources/#support" target="_blank" rel="noreferrer">{% trans 'Support' %}</a></li>
<li><a href="https://www.nexb.com/dejacode/" target="_blank" rel="noreferrer">{% trans 'About' %}</a></li>
<li><a href="https://aboutcode.org/dejacode/" target="_blank" rel="noreferrer">{% trans 'About' %}</a></li>
<li><a href="https://github.com/aboutcode-org/dejacode" target="_blank" rel="noreferrer">{% trans 'Source Code' %}</a></li>
<li><a href="https://github.com/aboutcode-org/dejacode/releases" target="_blank" rel="noreferrer">{% trans 'Releases' %}</a></li>
<li><a href="https://scancode-licensedb.aboutcode.org/agpl-3.0.html" target="_blank" rel="noreferrer">{% trans 'License' %}</a></li>
Expand Down
27 changes: 2 additions & 25 deletions dje/templates/includes/header.html
Original file line number Diff line number Diff line change
@@ -1,25 +1,2 @@
{% extends 'includes/navbar_header.html' %}
{% load i18n %}

{% block nav-brand %}
<div class="navbar-nav navbar-brand">
<div class="nav-item dropdown">
<a class="nav-link dropdown-toggle d-inline" href="#" data-bs-toggle="dropdown" aria-expanded="false">
{{ SITE_TITLE }}
</a>
<div class="dropdown-menu position-absolute">
<a class="dropdown-item" href="/">Home</a>{# No trans for Home on purpose #}
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="https://dejacode.readthedocs.io/en/latest/" target="_blank" rel="noreferrer">{% trans 'Documentation' %}</a>
<a class="dropdown-item" href="https://www.nexb.com/resources/#support" target="_blank" rel="noreferrer">{% trans 'Support' %}</a>
<a class="dropdown-item" href="https://www.nexb.com/dejacode/" target="_blank" rel="noreferrer">{% trans 'About' %}</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="https://github.com/aboutcode-org/dejacode" target="_blank" rel="noreferrer">{% trans 'Source Code' %}</a>
<a class="dropdown-item" href="https://github.com/aboutcode-org/dejacode/releases" target="_blank" rel="noreferrer">{% trans 'Releases' %}</a>
<a class="dropdown-item" href="https://scancode-licensedb.aboutcode.org/agpl-3.0.html" target="_blank" rel="noreferrer">{% trans 'License' %}</a>
<div class="dropdown-divider"></div>
<h6 class="dropdown-header">v{{ DEJACODE_VERSION }}</h6>
</div>
</div>
</div>
{% endblock %}
{% extends 'navbar/navbar_header.html' %}
{% load i18n %}
Loading
Loading