1

I'm using Django and Bootstrap. I come to you with a total of 3 interconnected problems, if you come up with a better idea on how to do all of this, I'm open to suggestions. Thanks in advance.


I have a base template which is extended by other templates and it contains navigation, in which I would like to have the name of the currently selected theme displayed. After clicking on this name, I want to have the option to select one of three themes: light, dark, custom. I started to do this using a dropdown:

                <li class="nav-item dropdown">
                    <button class="nav-link dropdown-toggle" id="navbarThemeDropdown" type="button" data-bs-toggle="dropdown" aria-expanded="false">
                        Theme: Light <i class="bi bi-sun-fill"></i>
                    </button>
                    <div class="dropdown-menu" aria-labelledby="navbarThemeDropdown">
                        <button class="dropdown-item d-flex justify-content-between" type="button">
                            Light <i class="bi bi-sun-fill"></i>
                        </button>
                        <button class="dropdown-item d-flex justify-content-between" type="button">
                            Dark <i class="bi bi-moon-fill"></i>
                        </button>
                        <button class="dropdown-item d-flex justify-content-between" type="button">
                            Custom <i class="bi bi-palette-fill"></i>
                        </button>
                    </div>
                </li>

Following the documentation https://getbootstrap.com/docs/5.3/customize/color-modes/#enable-dark-mode to apply the theme for all elements on the page, I thought to use a context processor, which will read the theme value from cookies:

<html lang="en" data-bs-theme="{{theme}}">

context_processors.py:

def theme(request):
    return {'theme': request.COOKIES.get('theme', 'light')}

But I don't know how to set these cookies after choosing one of the themes. Also notice that the theme function returns 'light' when there is no cookie, but it should also set this cookie then.


Logged in user should be able to choose colors of the navigation, the background of the page, and the background of Bootstrap cards for the custom theme in account settings. I thought to create the custom theme roughly like this:

base.css:

[data-bs-theme="custom"] {
  --bs-body-bg: var(--body-bg);
  --bs-navbar-bg: var(--navbar-bg);
  --bs-card-bg: var(--card-bg);

But I also don't know how to fetch these variables and whether I should store these colors in the database, creating three columns.

Kanapek
  • 51
  • 3
  • Does [this](https://stackoverflow.com/q/2551933/18018869) question with its answer help you? I would set a cookie with selected themename and then pass the themename to the base template like shown in the answer. I guess it is inevitable to write css files for each theme. In your template you can then via the themename decide which css file you want to load. Hope that makes sense... – Tarquinius Jul 19 '23 at 09:47

1 Answers1

0

Here I tried to solve your problem like this

models.py

class ThemeChanger(models.Model):
    is_dark = models.BooleanField(default=False)

views.py

from django.shortcuts import render, redirect
from .models import *
from .serializers import *

def theme_reference():
    theme_mode = ThemeChanger.objects.latest('id')
    return theme_mode.is_dark

def ThemeChangerView(request):
    theme_mode = ThemeChanger.objects.latest('id')
    if theme_mode.is_dark == False:
        theme_mode.is_dark = True
        theme_mode.save()
    else:
        theme_mode.is_dark = False
        theme_mode.save()          
    context = {'theme_mode':theme_mode.is_dark}
    return render(request,'index.html',context)

def DemoView(request):
    context = {'theme_mode':theme_reference()}
    return render(request,'index.html',context)

urls.py

from django.urls import path
from .views import *
 
urlpatterns = [
 
    path('', DemoView,name='home'),
    path('theme/', ThemeChangerView,name='theme'),
    
]

base.html

{% load static %}
<!doctype html>
<html lang="en" data-bs-theme="{% if theme_mode %}light{% else %}dark{% endif %}">
  
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>
    {% block title %}

    {% endblock title %}
  </title>
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
</head>

<body>
  <nav class="navbar navbar-expand-lg bg-body-tertiary">
    <div class="container-fluid">
      <a class="navbar-brand" href="#">Navbar</a>
      <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
      </button>
      <div class="collapse navbar-collapse" id="navbarSupportedContent">
        <ul class="navbar-nav me-auto mb-2 mb-lg-0">
          <li class="nav-item">
            <a class="nav-link active" aria-current="page" href="#">Home</a>
          </li>
          <li class="nav-item">
            <a class="nav-link" href="#">Link</a>
          </li>
          <li class="nav-item dropdown">
            <a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
              Dropdown
            </a>
            <ul class="dropdown-menu">
              <li><a class="dropdown-item" href="#">Action</a></li>
              <li><a class="dropdown-item" href="#">Another action</a></li>
              <li><hr class="dropdown-divider"></li>
              <li><a class="dropdown-item" href="#">Something else here</a></li>
            </ul>
          </li>
         
        </ul>
        <form class="d-flex" action="{% url 'theme' %}">
          <button class="btn btn-sm btn-outline-success" style="border-radius: 50%;" type="submit">{% if theme_mode %}<i class="bi bi-sun-fill">{% else %}<i class="bi bi-moon-stars-fill">{% endif %}</i></i></button>
        </form>
      </div>
    </div>
  </nav>
  {% block body %}

  {% endblock body %}
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>

</body>

</html>

index.html

{% extends "base.html" %}
{% load static %}
{% block title %}
     Index | Page 
{% endblock title %}
   
{% block body %}
<div class="container p-5">
  <div class="row mx-auto">
    <div class="col-lg-3">
      <div class="card">
        <img src="..." class="card-img-top" alt="...">
      
        <div class="card-body">
          <h5 class="card-title">Card title</h5>
          <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
          <a href="#" class="btn btn-primary">Go somewhere</a>
        </div>
      </div>
    </div>
    <div class="col-lg-3">
      <div class="card" >
        <img src="..." class="card-img-top" alt="...">
        <div class="card-body">
          <h5 class="card-title">Card title</h5>
          <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
          <a href="#" class="btn btn-primary">Go somewhere</a>
        </div>
      </div>
    </div>
    <div class="col-lg-3">
      <div class="card" >
        <img src="..." class="card-img-top" alt="...">
        <div class="card-body">
          <h5 class="card-title">Card title</h5>
          <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
          <a href="#" class="btn btn-primary">Go somewhere</a>
        </div>
      </div>
    </div>
    <div class="col-lg-3">
      <div class="card" >
        <img src="..." class="card-img-top" alt="...">
        <div class="card-body">
          <h5 class="card-title">Card title</h5>
          <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
          <a href="#" class="btn btn-primary">Go somewhere</a>
        </div>
      </div>
    </div>
    <div class="dropdown">
      <button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
        Dropdown button
      </button>
      <ul class="dropdown-menu">
        <li><a class="dropdown-item" href="#">Action</a></li>
        <li><a class="dropdown-item" href="#">Another action</a></li>
        <li><a class="dropdown-item" href="#">Something else here</a></li>
      </ul>
    </div>
  </div>
</div>
{% endblock body %}
   

Browser output

enter image description here

NOTE - here the tricky part is you need to pass theme_reference() function in context of every view