Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
1a82a3f
add uncommited styles on master
podliashanyk Aug 6, 2025
01bb330
Run npx @tailwindcss/upgrade
podliashanyk Aug 6, 2025
371fa0b
Fix breaking tailwind v4 changes that were not fixed automatically
podliashanyk Aug 6, 2025
bb23ff7
Fix breaking changes in daisyUI v5
podliashanyk Aug 6, 2025
1327230
fixup
podliashanyk Aug 6, 2025
48c5409
fixup
podliashanyk Aug 6, 2025
3ffa341
Add theme definition via CSS
podliashanyk Aug 13, 2025
05d7fa3
update styles
podliashanyk Aug 13, 2025
7999757
Use newest standalone tailwind cli
hmpf Aug 14, 2025
b205de3
Improve docstring of tailwind_config command
hmpf Aug 14, 2025
f5e5892
fix size of badges in incident list
hmpf Aug 14, 2025
0d3182a
modernize daisy label handling
hmpf Aug 14, 2025
54f5531
fix styles in filterbox
hmpf Aug 14, 2025
6a84f5d
fix dropdown size in refresh info
hmpf Aug 14, 2025
f3f8eb0
fix border color of tabs
hmpf Aug 15, 2025
5a5aaaa
fix top left corner in filterbox
hmpf Aug 15, 2025
ab3ceda
fix color of values in refresh info
hmpf Aug 15, 2025
5378e5b
fix position of refresh info selects
hmpf Aug 15, 2025
9d46a12
fix position and color in filterbox
hmpf Aug 15, 2025
fcdd173
fix broken divider
hmpf Aug 15, 2025
5162bb2
update tests
hmpf Aug 15, 2025
98a6ab5
move argus theme to separate css file
hmpf Aug 18, 2025
40bec75
fix "Error: Can't resolve 'snippets/10-tailwind.css'"
hmpf Aug 18, 2025
12412a4
fix: finding themes directly defined in css
hmpf Aug 18, 2025
9bbf8f5
Improve theme utils function names
hmpf Aug 18, 2025
5aaccd2
Move template helpers to separate utils file
hmpf Aug 18, 2025
a8cc937
Add theme from setting in new way
hmpf Aug 18, 2025
b45af55
Make tailwind_config command more debuggable
hmpf Aug 18, 2025
a386084
Support oldish way of adding themes
hmpf Aug 18, 2025
fbf428f
Update docs for how to add/change themes
hmpf Aug 18, 2025
10304ef
update styles
hmpf Aug 18, 2025
d2a3e5d
moodernize safelist
hmpf Aug 19, 2025
53e33ad
fixup! Add theme from setting in new way
hmpf Aug 19, 2025
43eb94b
fix severity
hmpf Aug 19, 2025
a1fa5bd
stop using tailwind.config.js
hmpf Aug 19, 2025
8aff5e4
fix label colors
hmpf Aug 20, 2025
d3afd86
removed removed DaisyUI class "input-bordered"
hmpf Aug 20, 2025
e36de73
make buttons and form field borders round
hmpf Aug 20, 2025
29e24f4
fix filter change dropdowns
hmpf Aug 21, 2025
b83a1e3
Experimental: fix buttons for altering stored filters
hmpf Aug 21, 2025
061b9e0
Update tailwindcss-extra architecture map
hmpf Aug 22, 2025
97598e2
Ensure stored filter list is in context
hmpf Aug 22, 2025
327835e
stop
hmpf Oct 7, 2025
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
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ testclean: coverageclean clean
nuke: clean docclean distclean testclean cacheclean

tailwind:
$(TAILWINDDIR)/tailwindcss -c $(TAILWINDDIR)/tailwind.config.js -i $(TAILWINDDIR)/styles.css -o $(STATICDIR)/styles.css
$(TAILWINDDIR)/tailwindcss -i $(TAILWINDDIR)/styles.css -o $(STATICDIR)/styles.css

tailwind-watch:
$(TAILWINDDIR)/tailwindcss -c $(TAILWINDDIR)/tailwind.config.js -i $(TAILWINDDIR)/styles.css -o $(STATICDIR)/styles.css --watch
Expand Down
220 changes: 163 additions & 57 deletions docs/customization/htmx-frontend.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,80 +41,186 @@ example.
Themes and styling
==================

How to customize the look:
How to choose which themes to be made available
-----------------------------------------------

This is controlled by the setting :setting:`DAISYUI_THEMES`. You need to run
the ``tailwind_config`` management command afterwards, followed by ``make
tailwind``.

How to add additional themes
----------------------------

See the `Daisy UI 5 theme generator <https://daisyui.com/theme-generator/>`_
for the themes that are shipped with Argus. You can also generate new themes
there. To add a pre-configured theme just add the name to the
:setting:`DAISYUI_THEMES` setting and run ``tailwind_config`` + ``make
tailwind`` as usual.

If generating a new theme:

1. Make sure the browser is in light mode if making a light theme, or dark mode
if making a dark theme.
2. Choose a name that is pure ASCII, and don't reuse any of the names that
comes pre-configured. Save the generated CSS to some file.

The ``argus`` theme is included in the file ``argus/htmx/tailwindtheme/snippets/25-theme-argus.css``. The format is::

@plugin "daisyui/theme" {
name: "argus";
default: false;
prefersdark: false;
color-scheme: "light";
--color-primary: #006d91;
--color-primary-content: #d1e1e9;
--color-secondary: #f3b61f;
--color-secondary-content: #140c00;
--color-accent: #c84700;
--color-accent-content: #f8dbd1;
--color-neutral: #006d91;
--color-neutral-content: #d1e1e9;
--color-base-100: #edfaff;
--color-base-200: #ced9de;
--color-base-300: #b0babd;
--color-base-content: #141516;
--color-info: #0073e5;
--color-info-content: #000512;
--color-success: #008700;
--color-success-content: #d3e7d1;
--color-warning: #ee4900;
--color-warning-content: #140200;
--color-error: #e5545a;
--color-error-content: #120203;
/* border radius */
--radius-selector: 2rem;
--radius-field: 0.25rem;
--radius-box: 0.5rem;

/* base sizes */
--size-selector: 0.25rem;
--size-field: 0.25rem;

/* border size */
--border: 1px;

/* effects */
--depth: 1;
--noise: 0;
}

The stuff starting with ``--`` is css-variables.

There are two different methods to install generated themes.

1. Via :setting:`DAISYUI_THEMES`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Instead of adding the name of a theme to the :setting:`DAISYUI_THEMES` setting
you can add an entire theme instead. Given the example theme above, it needs to
be converted to Python like so::

DAISYUI_THEMES = [
"light",
"dark",
{
"argus": {
"name": "argus",
"default": false",
"prefersdark": false",
"color-scheme": "light"",
"--color-primary": "#006d91",
"--color-primary-content": "#d1e1e9",
"--color-secondary": "#f3b61f",
"--color-secondary-content": "#140c00",
"--color-accent": "#c84700",
"--color-accent-content": "#f8dbd1",
"--color-neutral": "#006d91",
"--color-neutral-content": "#d1e1e9",
"--color-base-100": "#edfaff",
"--color-base-200": "#ced9de",
"--color-base-300": "#b0babd",
"--color-base-content": "#141516",
"--color-info": "#0073e5",
"--color-info-content": "#000512",
"--color-success": "#008700",
"--color-success-content": "#d3e7d1",
"--color-warning": "#ee4900",
"--color-warning-content": "#140200",
"--color-error": "#e5545a",
"--color-error-content": "#120203",
"--radius-selector": "2rem",
"--radius-field": "0.25rem",
"--radius-box": "0.5rem",
"--size-selector": "0.25rem",
"--size-field": "0.25rem",
"--border": "1px",
"--depth": "1",
"--noise": "0",
},
},
]

Make the above one of the entries in the :setting:`DAISYUI_THEMES` setting and
run ``tailwind_config`` + ``make tailwind`` as usual.

2. Via an app and css snippet
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Create a Django app which has a ``snippets`` directory, see
``argus.htmx.apps.HtmxFrontendConfig.tailwind_css_files`` for something to
copy.

In the snippets-directory, make a new file with the theme you generated before.
We recommend naming the file ``99-theme-THEMENAME.css``, where THEMENAME is the
name you chose when generating the theme.

Add the app to :setting:`INSTALLED_APPS`, the name to
:setting:`DAISYUI_THEMES`, and finish with ``tailwind_config`` + ``make
tailwind`` as usual.

* Override Argus' Tailwind CSS theme defaults and/or choose which daisyUI color
themes to include. You can do so by updating the default
:setting:`TAILWIND_THEME_OVERRIDE` and :setting:`DAISYUI_THEMES` settings
respectively before running a ``tailwind_config`` management command:
How to customize the look without switching themes
--------------------------------------------------

* Override Argus' Tailwind CSS theme defaults by updating the setting
:setting:`TAILWIND_THEME_OVERRIDE`.

Via environment variables, for example::

TAILWIND_THEME_OVERRIDE = '
{
"borderWidth": {
"DEFAULT": "1px"
},
"extend": {
"borderRadius": {
"4xl": "2rem"
}
}
}
'
DAISYUI_THEMES = '
[
"light",
"dark",
"cyberpunk",
"dim",
"autumn",
{ "mytheme": {
"color-scheme": "dark",
"primary": "#009eb6",
"primary-content": "#00090c",
"secondary": "#00ac00",
"secondary-content": "#000b00",
"accent": "#ff0000",
"accent-content": "#160000",
"neutral": "#262c0e",
"neutral-content": "#cfd1ca",
"base-100": "#292129",
"base-200": "#221b22",
"base-300": "#1c161c",
"base-content": "#d0cdd0",
"info": "#00feff",
"info-content": "#001616",
"success": "#b1ea50",
"success-content": "#0c1302",
"warning": "#d86d00",
"warning-content": "#110400",
"error": "#ff6280",
"error-content": "#160306"
TAILWIND_THEME_OVERRIDE = '
{
"borderWidth": {
"DEFAULT": "1px"
},
"extend": {
"borderRadius": {
"4xl": "2rem"
}
}
}
]
'
'

Or by providing corresponding values in your local settings that star-imports from an `argus-server`_ settings file::
Or by providing corresponding values in your local settings.

TAILWIND_THEME_OVERRIDE = {...}
DAISYUI_THEMES = [...]
Run ``tailwind_config`` to generate the configuratonm then ``make tailwind`` to
generate the final css-file, as usual.

Some links that may be relevant for the customization values mentioned above:
* `daisyUI themes`_
* `list of daisyUI color names`_
* `Tailwind CSS theme customization`_

* `daisyUI themes`_
* `list of daisyUI color names`_
* `Tailwind CSS theme customization`_

* Override the default main stylesheet path by setting
``ARGUS_STYLESHEET_PATH`` in the environment. The path is under
``STATIC_URL``. This depends on the context processor
``argus.htmx.context_processors.path_to_stylesheet``.
* Include additional styles/stylesheets using the ``head`` block in your templates.
* Generate a Tailwind config file by running the ``tailwind_config`` management
command. By default the generated file will be based on
``src/argus/htmx/tailwindtheme/tailwind.config.template.js`` and expected
values will be injected with reasonable defaults.
command. It will be placed in
``src/argus/htmx/tailwindtheme/tailwind.config.js``. By default the generated
file will be based on
``src/argus/htmx/templates/tailwind/tailwind.config.js`` and expected values
will be injected with reasonable defaults.

Incident table column customization
===================================
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ Create the following template ``htmx/incident/_my_custom_action_modal.html``::

{% extends "htmx/incident/_base_incident_update_modal.html" %}
{% block dialogform %}
<label class="indicator input input-bordered flex items-center gap-2 w-full">
<label class="indicator input flex items-center gap-2 w-full">
Custom Field
<span class="indicator-item indicator-top indicator-start badge border-none mask mask-circle text-warning text-base">*</span>
<input name="custom_field"
Expand Down
26 changes: 1 addition & 25 deletions src/argus/htmx/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,31 +33,7 @@
DEFAULT_THEMES = [
"dark",
"light",
{
"argus": {
"color-scheme": "light",
"primary": "#006d91",
"primary-content": "#d1e1e9",
"secondary": "#f3b61f",
"secondary-content": "#140c00",
"accent": "#c84700",
"accent-content": "#f8dbd1",
"neutral": "#006d91",
"neutral-content": "#d1e1e9",
"base-100": "#edfaff",
"base-200": "#ced9de",
"base-300": "#b0babd",
"base-content": "#141516",
"info": "#0073e5",
"info-content": "#000512",
"success": "#008700",
"success-content": "#d3e7d1",
"warning": "#ee4900",
"warning-content": "#140200",
"error": "#e5545a",
"error-content": "#120203",
}
},
"argus",
]
DAISYUI_THEMES = get_json_env("DAISYUI_THEMES", DEFAULT_THEMES, quiet=True)
THEME_DEFAULT = get_str_env("ARGUS_THEME_DEFAULT", "argus")
Expand Down
2 changes: 1 addition & 1 deletion src/argus/htmx/destination/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class Meta:
"label": "Name",
}
widgets = {
"media": forms.Select(attrs={"class": "select input-bordered w-full max-w-xs"}),
"media": forms.Select(attrs={"class": "select w-full max-w-xs"}),
}

def clean(self):
Expand Down
7 changes: 6 additions & 1 deletion src/argus/htmx/incident/filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class IncidentFilterForm(forms.Form):
widget=forms.TextInput(
attrs={
"placeholder": "key=value, ...",
"class": "input input-primary input-bordered input-sm overflow-y-auto min-h-8 h-auto max-h-16 max-w-xs leading-tight",
"class": "input input-primary input-sm overflow-y-auto min-h-8 h-auto max-h-16 max-w-xs leading-tight",
}
),
required=False,
Expand Down Expand Up @@ -151,6 +151,11 @@ def get_queryset(self):
def get_success_url(self):
return reverse("htmx:filter-list")

def get_context_data(self, **kwargs):
context = super().get_context_sdata(**kwargs)
context["stored_filters"] = context["object_list"]
return context


def incident_list_filter(request, qs, use_empty_filter=False):
filter_pk, filter_obj = request.session.get("selected_filter", None), None
Expand Down
2 changes: 1 addition & 1 deletion src/argus/htmx/incident/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class TimeframeForm(forms.Form):
initial=TIMEFRAME_DEFAULT,
widget=forms.Select(
attrs={
"class": "select select-xs bg-transparent text-base border-none -ml-2",
"class": "select bg-transparent text-base text-base-content border-none p-0",
"autocomplete": "off",
"hx-get": ".",
"hx-trigger": "change",
Expand Down
23 changes: 19 additions & 4 deletions src/argus/htmx/incident/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ def delete_filter(request: HtmxHttpRequest, pk: int):
def get_existing_filters(request: HtmxHttpRequest):
existing_filters = Filter.objects.all().filter(user=request.user)
if existing_filters:
context = {"filters": existing_filters}
context = {"stored_filters": existing_filters}
if request.htmx.target == "delete-filter-items":
context.update({"action": "delete"})
return render(request, "htmx/incident/_existing_filters.html", context=context)
Expand Down Expand Up @@ -208,6 +208,12 @@ def incident_list(request: HtmxHttpRequest) -> HttpResponse:
total_count = qs.count()
last_refreshed = make_aware(datetime.now())

# Stored filters
existing_filters = Filter.objects.filter(user=request.user)
stored_filter_pk = request.session.get("selected_filter", None)
stored_filter_obj = existing_filters.filter(pk=stored_filter_pk).first()
stored_filter_name = stored_filter_obj.name if stored_filter_obj else ""

# make dict from QueryDict
params = dict(request.GET.items())

Expand Down Expand Up @@ -242,14 +248,23 @@ def incident_list(request: HtmxHttpRequest) -> HttpResponse:
base_template = "htmx/incident/_base.html"
last_page_num = page.paginator.num_pages
context = {
"page_title": "Incidents",
"base": base_template,
# filter box
"filter_form": filter_form,
# storing filters
"stored_filters": existing_filters,
"stored_filter_pk": stored_filter_pk,
"stored_filter_name": stored_filter_name,
"update_stored_filter_button": f"Update {stored_filter_name}",
"delete_stored_filter_button": f"Delete {stored_filter_name}",
Comment on lines +259 to +260
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The filter name could be quite long, so including it in the button text makes the UI cluttered. Maybe just keep it as "Update filter" and "Delete filter"? The name in the select and in the confirmation dialog gives enough context to which filter is being updated/deleted.

# table
"columns": columns,
# refresh info
"filtered_count": filtered_count,
"count": total_count,
"filter_form": filter_form,
"timeframe_form": timeframe_form,
"timeframe": timeframe,
"page_title": "Incidents",
"base": base_template,
"page": page,
"last_page_num": last_page_num,
"second_to_last_page": last_page_num - 1,
Expand Down
Loading
Loading