Skip to content

Commit

Permalink
feat: light and black mode
Browse files Browse the repository at this point in the history
  • Loading branch information
somehowchris committed Jan 28, 2025
1 parent 411a9f6 commit d7178c7
Show file tree
Hide file tree
Showing 23 changed files with 295 additions and 83 deletions.
7 changes: 2 additions & 5 deletions src/riskmatrix/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
from riskmatrix.route_factories import root_factory
from riskmatrix.security import authenticated_user
from riskmatrix.security_policy import SessionSecurityPolicy
from openai import OpenAI
from anthropic import Anthropic
from langchain_openai import ChatOpenAI
from langchain_anthropic import ChatAnthropic

Expand Down Expand Up @@ -95,7 +93,7 @@ def main(
if openai_apikey := settings.get('openai_api_key'):
openai_client = ChatOpenAI(
api_key=openai_apikey,
model = "gpt-4o-mini",
model="gpt-4o-mini",
temperature=0.7
)
config.add_request_method(
Expand All @@ -114,7 +112,7 @@ def main(
'llm',
reify=True
)

if langfuse_host := settings.get("langfuse_host"):
from langfuse.callback import CallbackHandler
langfuse_handler = CallbackHandler(
Expand All @@ -127,7 +125,6 @@ def main(
'langfuse',
reify=True
)


app = config.make_wsgi_app()
return Fanstatic(app, versioning=True)
29 changes: 10 additions & 19 deletions src/riskmatrix/layouts/layout.pt
Original file line number Diff line number Diff line change
Expand Up @@ -5,52 +5,45 @@
i18n:domain="riskmatrix"
lang="${layout.locale_name()}"
class="h-100"
data_sentry_dsn="${layout.sentry_dsn()}">
data_sentry_dsn="${layout.sentry_dsn()}"
data-bs-theme="dark">

<head>

<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />

<tal:block tal:condition="layout.sentry_dsn()">
<script type="text/javascript" src="${layout.static_url('riskmatrix:static/js/bundle.min.js')}"></script>
<script type="text/javascript" src="${layout.static_url('riskmatrix:static/js/sentry.js')}"></script>
<script type="text/javascript" src="${layout.static_url('riskmatrix:static/js/bundle.min.js')}" nonce="${request.csp_nonce}"></script>
<script type="text/javascript" src="${layout.static_url('riskmatrix:static/js/sentry.js')}" nonce="${request.csp_nonce}"></script>
</tal:block>
<script type="text/javascript" src="${layout.static_url('riskmatrix:static/js/plotly.min.js')}"></script>
<script type="text/javascript" src="${layout.static_url('riskmatrix:static/js/marked.min.js')}"></script>

<title>RiskMatrix<tal:b tal:condition="exists:title"> — ${title}</tal:b></title>
<script type="text/javascript" src="${layout.static_url('riskmatrix:static/js/plotly.min.js')}" nonce="${request.csp_nonce}"></script>
<script type="text/javascript" src="${layout.static_url('riskmatrix:static/js/marked.min.js')}" nonce="${request.csp_nonce}"></script>
<script type="text/javascript" src="${layout.static_url('riskmatrix:static/js/plotly_theme.js')}" nonce="${request.csp_nonce}"></script>

<title>RiskMatrix<tal:b tal:condition="exists:title"> — ${title}</tal:b></title>
</head>

<body class="d-flex flex-column h-100">

${panel('navbar')}

<!-- Begin page content -->
<main class="flex-shrink-0">

${panel('flash')}

<div class="container">

<div class="row" tal:omit-tag="not:layout.show_steps()">

<div class="col-md-auto" tal:condition="layout.show_steps()">
${panel('steps')}
</div>

<div class="col" tal:omit-tag="not:layout.show_steps()">
<tal:block metal:define-slot="content" />
</div>
</div>

</div>

<tal:block metal:define-slot="modals" />

</main>

<!-- Footer Content -->
<footer class="footer mt-auto py-3 bg-dark">
<div class="container">
<div class="row">
Expand Down Expand Up @@ -108,7 +101,5 @@
</div>
</div>
</footer>

</body>

</html>
30 changes: 30 additions & 0 deletions src/riskmatrix/layouts/navbar.pt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,36 @@
</li>
</ul>
<a class="btn btn-outline-light" href="${request.route_url('logout')}"><i class="fad fa-sign-out"></i> <tal:b i18n:translate>Logout</tal:b></a>
&nbsp;
<div class="dropdown">
<button class="btn btn-link nav-link py-2 px-0 px-lg-2 dropdown-toggle d-flex align-items-center" id="bd-theme" type="button" aria-expanded="false" data-bs-toggle="dropdown" data-bs-display="static" aria-label="Toggle theme (light)">
<i class="fa fa-sun theme-icon-active" aria-hidden="true"></i>
<span class="d-lg-none ms-2" id="bd-theme-text">Toggle theme</span>
</button>
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="bd-theme-text">
<li>
<button type="button" class="dropdown-item d-flex align-items-center" data-bs-theme-value="light" aria-pressed="true">
<i class="fa fa-sun" aria-hidden="true"></i>
&nbsp;
Light
</button>
</li>
<li>
<button type="button" class="dropdown-item d-flex align-items-center" data-bs-theme-value="dark" aria-pressed="false">
<i class="fa fa-moon" aria-hidden="true"></i>
&nbsp;
Dark
</button>
</li>
<li>
<button type="button" class="dropdown-item d-flex align-items-center" data-bs-theme-value="auto" aria-pressed="false">
<i class="fa fa-laptop" aria-hidden="true"></i>
&nbsp;
Auto
</button>
</li>
</ul>
</div>
</div>
</div>
</nav>
Expand Down
4 changes: 3 additions & 1 deletion src/riskmatrix/layouts/navbar.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ def navbar(context: object, request: 'IRequest') -> 'RenderData':
request,
_('Risk Catalog'),
request.route_url('risk_catalog'),
lambda request, url: request.path_url.startswith(request.route_url('risk_catalog'))
lambda request, url: request.path_url.startswith(
request.route_url('risk_catalog')
)
),
NavbarEntry(
request,
Expand Down
10 changes: 1 addition & 9 deletions src/riskmatrix/layouts/steps.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
from typing import NamedTuple
from typing import TYPE_CHECKING

from riskmatrix.models.risk_assessment import RiskAssessment
from riskmatrix.models.risk_assessment_info import RiskAssessmentInfo, RiskAssessmentState
if TYPE_CHECKING:
from pyramid.interfaces import IRequest

Expand All @@ -20,12 +18,6 @@ class Step(NamedTuple):


def steps(context: 'Organization', request: 'IRequest') -> 'RenderData':
assessments = request.dbsession.query(RiskAssessmentInfo).filter(
RiskAssessmentInfo.organization_id == context.id,
RiskAssessmentInfo.state == RiskAssessmentState.OPEN,
).all()

t = request.dbsession.query(RiskAssessment).filter(RiskAssessment.risk_assessment_info_id.in_([a.id for a in assessments]), RiskAssessment.likelihood == None, RiskAssessment.impact == None).count()
return {
'steps': [
Step(
Expand All @@ -49,7 +41,7 @@ def steps(context: 'Organization', request: 'IRequest') -> 'RenderData':
'#',
disabled=True
),
Step(_("Finish Assessment"), request.route_url('finish_assessment'), disabled=False),#t > 0 or len(assessments) == 0),
Step(_("Finish Assessment"), request.route_url('finish_assessment'), disabled=False),
]
}

Expand Down
2 changes: 1 addition & 1 deletion src/riskmatrix/mail/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@
'MailError',
'MailState',
'PostmarkMailer',
)
)
2 changes: 1 addition & 1 deletion src/riskmatrix/mail/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ class MailConnectionError(MailError, ConnectionError):


class InactiveRecipient(MailError):
pass
pass
2 changes: 1 addition & 1 deletion src/riskmatrix/mail/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,4 @@ def delete_template(template: 'ITemplate') -> list[str]:
Deletes a mailer template based on a certificate template.
Returns a list of errors. If the list is empty, it was successful.
"""
"""
2 changes: 1 addition & 1 deletion src/riskmatrix/mail/mailer.py
Original file line number Diff line number Diff line change
Expand Up @@ -622,4 +622,4 @@ def delete_template(self, template: 'ITemplate') -> list[str]:
'Transient': 0, # Needs to have lower priority than hard bounce
'Bounced': MailState.failed, # This is a hard bounce
'Opened': MailState.read,
}
}
1 change: 1 addition & 0 deletions src/riskmatrix/models/asset.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

from sqlalchemy_serializer import SerializerMixin


class Asset(Base, SoftDeleteMixin, SerializerMixin):

__tablename__ = 'asset'
Expand Down
5 changes: 3 additions & 2 deletions src/riskmatrix/static/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,11 @@ def css(
bootstrap_css = css('custom.css', depends=[fontawesome_css, bootstrap])
datatable_css = css('dataTables.bootstrap5.min.css', depends=[bootstrap])

popper = js('popper.min.js')
jquery = js('jquery.min.js')
datatable_core = js('jquery.dataTables.min.js', depends=[jquery])
bootstrap_core = js('bootstrap.bundle.min.js')
bootstrap_js = js('bootstrap_custom.js', depends=[jquery, bootstrap_core])
bootstrap_core = js('bootstrap.bundle.min.js', depends=[jquery, popper])
bootstrap_js = js('bootstrap_custom.js', depends=[jquery, bootstrap_core, popper])
datatable_bootstrap = js(
'dataTables.bootstrap5.min.js', depends=[bootstrap_core, datatable_core]
)
Expand Down
7 changes: 3 additions & 4 deletions src/riskmatrix/static/css/bootstrap.min.css

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/riskmatrix/static/css/bootstrap.min.css.map

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions src/riskmatrix/static/js/bootstrap.bundle.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/riskmatrix/static/js/bootstrap.bundle.min.js.map

Large diffs are not rendered by default.

101 changes: 101 additions & 0 deletions src/riskmatrix/static/js/bootstrap_custom.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,104 @@ $(function() {
// initialize tooltips
new bootstrap.Tooltip(document.body, {selector: '[data-bs-toggle="tooltip"]'});
});


/*!
* Color mode toggler for Bootstrap's docs (https://getbootstrap.com/)
* Copyright 2011-2024 The Bootstrap Authors
* Licensed under the Creative Commons Attribution 3.0 Unported License.
*/

(() => {
'use strict'

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

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

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

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

if (!themeSwitcher) {
return
}

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

// Remove all existing icon classes except 'theme-icon-active'
activeThemeIcon.className = 'fa theme-icon-active'

// Add the appropriate icon class based on the theme
if (theme === 'dark' || (theme === 'auto' && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
activeThemeIcon.classList.add('fa-moon')
} else if (theme === 'light' || (theme === 'auto' && !window.matchMedia('(prefers-color-scheme: dark)').matches)) {
activeThemeIcon.classList.add('fa-sun')
} else if (theme === 'auto') {
activeThemeIcon.classList.add('fa-laptop')
}

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')
const themeSwitcherLabel = `${themeSwitcherText.textContent} (${btnToActive.dataset.bsThemeValue})`
themeSwitcher.setAttribute('aria-label', themeSwitcherLabel)

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

const setTheme = theme => {
const resolvedTheme = theme === 'auto' ?
(window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')
: theme;

document.documentElement.setAttribute('data-bs-theme', resolvedTheme)

// Create and dispatch the theme change event
const event = new CustomEvent('bs-theme-changed', {
detail: { theme: resolvedTheme }
});
document.documentElement.dispatchEvent(event);

// Update the theme icon
showActiveTheme(theme);
}

window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
const storedTheme = getStoredTheme()
if (storedTheme !== 'light' && storedTheme !== 'dark') {
setTheme(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)
})
})
})

// Initialize theme
setTheme(getPreferredTheme())
})()
Loading

0 comments on commit d7178c7

Please sign in to comment.