mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-17 05:41:25 +02:00
Merge pull request #3726 from modoboa/apply-theme-to-login-pages
Apply custom theme to login page also.
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
import { ref } from 'vue'
|
||||
import { useTheme } from 'vuetify'
|
||||
import themeApi from '@/api/theme'
|
||||
|
||||
export function useModoboaTheme() {
|
||||
const vTheme = useTheme()
|
||||
const theme = ref(null)
|
||||
|
||||
const enableTheme = async () => {
|
||||
const response = await themeApi.getTheme()
|
||||
|
||||
theme.value = response.data
|
||||
if (
|
||||
theme.value.theme_primary_color !==
|
||||
vTheme.themes.value.light.colors.primary
|
||||
) {
|
||||
vTheme.themes.value.light.colors.primary = theme.value.theme_primary_color
|
||||
}
|
||||
if (
|
||||
theme.value.theme_primary_color_light !==
|
||||
vTheme.themes.value.light.colors['primary-lighten-1']
|
||||
) {
|
||||
vTheme.themes.value.light.colors['primary-lighten-1'] =
|
||||
theme.value.theme_primary_color_light
|
||||
}
|
||||
if (
|
||||
theme.value.theme_primary_color_dark !==
|
||||
vTheme.themes.value.light.colors['primary-darken-1']
|
||||
) {
|
||||
vTheme.themes.value.light.colors['primary-darken-1'] =
|
||||
theme.value.theme_primary_color_dark
|
||||
}
|
||||
if (
|
||||
theme.value.theme_secondary_color !==
|
||||
vTheme.themes.value.light.colors.secondary
|
||||
) {
|
||||
vTheme.themes.value.light.colors.secondary =
|
||||
theme.value.theme_secondary_color
|
||||
}
|
||||
if (
|
||||
theme.value.theme_label_color !== vTheme.themes.value.light.colors.label
|
||||
) {
|
||||
vTheme.themes.value.light.colors.label = theme.value.theme_label_color
|
||||
}
|
||||
}
|
||||
|
||||
return { theme, enableTheme }
|
||||
}
|
||||
@@ -26,17 +26,16 @@
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
import { useTheme } from 'vuetify'
|
||||
import { useAuthStore, useBusStore } from '@/stores'
|
||||
import { useModoboaTheme } from '@/composables/theme'
|
||||
import ConnectedView from './ConnectedView.vue'
|
||||
import NavBar from '@/components/shared/NavBar.vue'
|
||||
import TopMenu from '@/components/shared/TopMenu.vue'
|
||||
import themeApi from '@/api/theme'
|
||||
|
||||
const authStore = useAuthStore()
|
||||
const busStore = useBusStore()
|
||||
const { $gettext } = useGettext()
|
||||
const theme = useTheme()
|
||||
const { enableTheme } = useModoboaTheme()
|
||||
|
||||
const props = defineProps({
|
||||
color: {
|
||||
@@ -69,41 +68,7 @@ busStore.$onAction(({ name, after }) => {
|
||||
}, true)
|
||||
|
||||
if (props.loadTheme) {
|
||||
themeApi.getTheme().then((response) => {
|
||||
if (
|
||||
response.data.theme_primary_color !==
|
||||
theme.themes.value.light.colors.primary
|
||||
) {
|
||||
theme.themes.value.light.colors.primary =
|
||||
response.data.theme_primary_color
|
||||
}
|
||||
if (
|
||||
response.data.theme_primary_color_light !==
|
||||
theme.themes.value.light.colors['primary-lighten-1']
|
||||
) {
|
||||
theme.themes.value.light.colors['primary-lighten-1'] =
|
||||
response.data.theme_primary_color_light
|
||||
}
|
||||
if (
|
||||
response.data.theme_primary_color_dark !==
|
||||
theme.themes.value.light.colors['primary-darken-1']
|
||||
) {
|
||||
theme.themes.value.light.colors['primary-darken-1'] =
|
||||
response.data.theme_primary_color_dark
|
||||
}
|
||||
if (
|
||||
response.data.theme_secondary_color !==
|
||||
theme.themes.value.light.colors.secondary
|
||||
) {
|
||||
theme.themes.value.light.colors.secondary =
|
||||
response.data.theme_secondary_color
|
||||
}
|
||||
if (
|
||||
response.data.theme_label_color !== theme.themes.value.light.colors.label
|
||||
) {
|
||||
theme.themes.value.light.colors.label = response.data.theme_label_color
|
||||
}
|
||||
})
|
||||
await enableTheme()
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,30 +1,34 @@
|
||||
<script setup>
|
||||
import { onMounted } from 'vue'
|
||||
import { useAuthStore } from '@/stores'
|
||||
import { useModoboaTheme } from '@/composables/theme'
|
||||
|
||||
const props = defineProps({
|
||||
redirectUrl: String,
|
||||
})
|
||||
|
||||
const authStore = useAuthStore()
|
||||
const { enableTheme } = useModoboaTheme()
|
||||
|
||||
onMounted(() => {
|
||||
authStore.completeLogin(props.redirectUrl)
|
||||
})
|
||||
|
||||
await enableTheme()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-container class="fill-height" fluid>
|
||||
<v-row align="center" justify="center">
|
||||
<v-col cols="auto" class="text-center">
|
||||
<h1 class="ma-5">{{ $gettext('Attempting to log you in.') }}</h1>
|
||||
<v-progress-circular
|
||||
color="primary"
|
||||
indeterminate
|
||||
:size="128"
|
||||
:width="12"
|
||||
align-self="center"
|
||||
></v-progress-circular>
|
||||
<h1 class="ma-5">{{ $gettext('Attempting to log you in.') }}</h1>
|
||||
<v-progress-circular
|
||||
color="primary"
|
||||
indeterminate
|
||||
:size="128"
|
||||
:width="12"
|
||||
align-self="center"
|
||||
></v-progress-circular>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
|
||||
@@ -37,6 +37,23 @@ from .. import signals
|
||||
logger = logging.getLogger("modoboa.auth")
|
||||
|
||||
|
||||
class ModoboaThemeMixin:
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.parameters = dict(param_tools.get_global_parameters(app="core"))
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context.update(
|
||||
{
|
||||
"theme_primary_color": self.parameters["theme_primary_color"],
|
||||
"theme_primary_color_dark": self.parameters["theme_primary_color_dark"],
|
||||
}
|
||||
)
|
||||
return context
|
||||
|
||||
|
||||
class LoginViewMixin:
|
||||
@cached_property
|
||||
def logger(self):
|
||||
@@ -74,7 +91,7 @@ class LoginViewMixin:
|
||||
return response
|
||||
|
||||
|
||||
class LoginView(LoginViewMixin, auth_views.LoginView):
|
||||
class LoginView(ModoboaThemeMixin, LoginViewMixin, auth_views.LoginView):
|
||||
"""Login view with 2FA support."""
|
||||
|
||||
form_class = forms.AuthenticationForm
|
||||
@@ -86,13 +103,15 @@ class LoginView(LoginViewMixin, auth_views.LoginView):
|
||||
sender="login", location="loginpage"
|
||||
)
|
||||
announcements = [announcement[1] for announcement in announcements]
|
||||
context.update({"announcements": announcements})
|
||||
context.update(
|
||||
{
|
||||
"announcements": announcements,
|
||||
}
|
||||
)
|
||||
return context
|
||||
|
||||
def check_password_hash(self, user, form):
|
||||
condition = user.is_local and param_tools.get_global_parameter(
|
||||
"update_scheme", raise_exception=False
|
||||
)
|
||||
condition = user.is_local and self.parameters.get("update_scheme")
|
||||
if not condition:
|
||||
return
|
||||
# check if password scheme is correct
|
||||
@@ -157,7 +176,7 @@ def dologout(request):
|
||||
return HttpResponseRedirect(reverse("core:login"))
|
||||
|
||||
|
||||
class PasswordResetView(auth_views.PasswordResetView):
|
||||
class PasswordResetView(ModoboaThemeMixin, auth_views.PasswordResetView):
|
||||
"""Custom view to override form."""
|
||||
|
||||
form_class = forms.PasswordResetForm
|
||||
@@ -202,7 +221,7 @@ class PasswordResetView(auth_views.PasswordResetView):
|
||||
return HttpResponseRedirect(reverse("password_reset_confirm_code"))
|
||||
|
||||
|
||||
class VerifySMSCodeView(generic.FormView):
|
||||
class VerifySMSCodeView(ModoboaThemeMixin, generic.FormView):
|
||||
"""View to verify a code received by SMS."""
|
||||
|
||||
form_class = forms.VerifySMSCodeForm
|
||||
@@ -254,7 +273,7 @@ class ResendSMSCodeView(generic.View):
|
||||
return JsonResponse({"status": "ok"})
|
||||
|
||||
|
||||
class TwoFactorCodeVerifyView(LoginViewMixin, generic.FormView):
|
||||
class TwoFactorCodeVerifyView(ModoboaThemeMixin, LoginViewMixin, generic.FormView):
|
||||
"""View to verify a 2FA code after login."""
|
||||
|
||||
form_class = forms.Verify2FACodeForm
|
||||
|
||||
@@ -23,11 +23,6 @@ body {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.left-column {
|
||||
background-color: #046bf8;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.right-column {
|
||||
background-color: #ffffff;
|
||||
display: flex;
|
||||
@@ -115,29 +110,14 @@ h2 {
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-color: #c9c9c9;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
|
||||
.footer {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.footer a {
|
||||
color: #007bff;
|
||||
text-decoration: none;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.footer a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
@@ -155,6 +135,13 @@ h2 {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.annoucement {
|
||||
background-color: #e6e6e6;
|
||||
padding: 20px;
|
||||
border-radius: 5px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.container {
|
||||
flex-direction: column;
|
||||
|
||||
@@ -8,6 +8,24 @@
|
||||
<title>{% trans "Welcome to Modoboa" %}</title>
|
||||
<link rel="icon" type="image/x-icon" href="{% static 'css/favicon.ico' %}" />
|
||||
<link rel="stylesheet" type="text/css" href="{% static 'css/offline.css' %}" />
|
||||
<style>
|
||||
.left-column {
|
||||
background-color: {{ theme_primary_color }};
|
||||
text-align: center;
|
||||
}
|
||||
.btn-primary {
|
||||
background-color: {{ theme_primary_color }};
|
||||
color: white;
|
||||
}
|
||||
.btn-primary:hover {
|
||||
background-color: {{ theme_primary_color_dark }};
|
||||
}
|
||||
.footer a {
|
||||
color: #{{ theme_primary_color }};
|
||||
text-decoration: none;
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
||||
{% block extra_css %}{% endblock %}
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
{% block sub_content %}
|
||||
{% for announcement in announcements %}
|
||||
<div>{{ announcement|safe }}</div>
|
||||
<div class="annoucement">{{ announcement|safe }}</div>
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user