nexui 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nexui/__init__.py +0 -0
- nexui/asgi.py +16 -0
- nexui/settings.py +148 -0
- nexui/templates/base.html +11 -0
- nexui/templates/components/button.html +44 -0
- nexui/templates/components/button_old_1.html +80 -0
- nexui/templates/components/card.html +4 -0
- nexui/templates/components/modal.html +0 -0
- nexui/templates/components/tabs.html +0 -0
- nexui/templates/components/toast.html +0 -0
- nexui/templates/form.html +59 -0
- nexui/templates/index.html +90 -0
- nexui/templates/index_old_1.html +182 -0
- nexui/templates/result.html +2 -0
- nexui/templatetags/__init__.py +0 -0
- nexui/templatetags/__pycache__/__init__.cpython-313.pyc +0 -0
- nexui/templatetags/__pycache__/custom_filters.cpython-313.pyc +0 -0
- nexui/templatetags/__pycache__/custom_tags.cpython-313.pyc +0 -0
- nexui/templatetags/__pycache__/nexui_tags.cpython-313.pyc +0 -0
- nexui/templatetags/__pycache__/nexui_tags_old_1.cpython-313.pyc +0 -0
- nexui/templatetags/nexui_tags.py +102 -0
- nexui/templatetags/nexui_tags_old_1.py +58 -0
- nexui/urls.py +29 -0
- nexui/views.py +33 -0
- nexui/wsgi.py +16 -0
- nexui-0.1.0.dist-info/LICENSE +21 -0
- nexui-0.1.0.dist-info/METADATA +176 -0
- nexui-0.1.0.dist-info/RECORD +30 -0
- nexui-0.1.0.dist-info/WHEEL +5 -0
- nexui-0.1.0.dist-info/top_level.txt +1 -0
nexui/__init__.py
ADDED
|
File without changes
|
nexui/asgi.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ASGI config for nexui project.
|
|
3
|
+
|
|
4
|
+
It exposes the ASGI callable as a module-level variable named ``application``.
|
|
5
|
+
|
|
6
|
+
For more information on this file, see
|
|
7
|
+
https://docs.djangoproject.com/en/5.1/howto/deployment/asgi/
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
|
|
12
|
+
from django.core.asgi import get_asgi_application
|
|
13
|
+
|
|
14
|
+
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'nexui.settings')
|
|
15
|
+
|
|
16
|
+
application = get_asgi_application()
|
nexui/settings.py
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Django settings for nexui project.
|
|
3
|
+
|
|
4
|
+
Generated by 'django-admin startproject' using Django 5.1.5.
|
|
5
|
+
|
|
6
|
+
For more information on this file, see
|
|
7
|
+
https://docs.djangoproject.com/en/5.1/topics/settings/
|
|
8
|
+
|
|
9
|
+
For the full list of settings and their values, see
|
|
10
|
+
https://docs.djangoproject.com/en/5.1/ref/settings/
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import os
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
|
|
16
|
+
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
|
17
|
+
BASE_DIR = Path(__file__).resolve().parent.parent
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# Quick-start development settings - unsuitable for production
|
|
21
|
+
# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/
|
|
22
|
+
|
|
23
|
+
# SECURITY WARNING: keep the secret key used in production secret!
|
|
24
|
+
SECRET_KEY = 'django-insecure-p)pmps#lul61h5nv-56@bym!_v+abj*3o%%+w^)t)mcwv9&zw9'
|
|
25
|
+
|
|
26
|
+
# SECURITY WARNING: don't run with debug turned on in production!
|
|
27
|
+
DEBUG = True
|
|
28
|
+
|
|
29
|
+
ALLOWED_HOSTS = []
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# Application definition
|
|
33
|
+
|
|
34
|
+
INSTALLED_APPS = [
|
|
35
|
+
'django.contrib.admin',
|
|
36
|
+
'django.contrib.auth',
|
|
37
|
+
'django.contrib.contenttypes',
|
|
38
|
+
'django.contrib.sessions',
|
|
39
|
+
'django.contrib.messages',
|
|
40
|
+
'django.contrib.staticfiles',
|
|
41
|
+
'tailwind',
|
|
42
|
+
'theme',
|
|
43
|
+
'django_browser_reload',
|
|
44
|
+
"django_htmx",
|
|
45
|
+
'nexui',
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
# ? Tailwind configuration
|
|
49
|
+
TAILWIND_APP_NAME = 'theme'
|
|
50
|
+
|
|
51
|
+
INTERNAL_IPS = [
|
|
52
|
+
"127.0.0.1",
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
NPM_BIN_PATH = "C:/Program Files/nodejs/npm.cmd"
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
MIDDLEWARE = [
|
|
60
|
+
'django.middleware.security.SecurityMiddleware',
|
|
61
|
+
'django.contrib.sessions.middleware.SessionMiddleware',
|
|
62
|
+
'django.middleware.common.CommonMiddleware',
|
|
63
|
+
"django_browser_reload.middleware.BrowserReloadMiddleware",
|
|
64
|
+
"django_htmx.middleware.HtmxMiddleware",
|
|
65
|
+
'django.middleware.csrf.CsrfViewMiddleware',
|
|
66
|
+
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
|
67
|
+
'django.contrib.messages.middleware.MessageMiddleware',
|
|
68
|
+
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
ROOT_URLCONF = 'nexui.urls'
|
|
72
|
+
|
|
73
|
+
TEMPLATES = [
|
|
74
|
+
{
|
|
75
|
+
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
|
76
|
+
# 'DIRS': [],
|
|
77
|
+
'DIRS': [BASE_DIR / 'templates'],
|
|
78
|
+
'APP_DIRS': True,
|
|
79
|
+
'OPTIONS': {
|
|
80
|
+
'context_processors': [
|
|
81
|
+
'django.template.context_processors.debug',
|
|
82
|
+
'django.template.context_processors.request',
|
|
83
|
+
'django.contrib.auth.context_processors.auth',
|
|
84
|
+
'django.contrib.messages.context_processors.messages',
|
|
85
|
+
],
|
|
86
|
+
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
]
|
|
90
|
+
|
|
91
|
+
WSGI_APPLICATION = 'nexui.wsgi.application'
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
# Database
|
|
95
|
+
# https://docs.djangoproject.com/en/5.1/ref/settings/#databases
|
|
96
|
+
|
|
97
|
+
DATABASES = {
|
|
98
|
+
'default': {
|
|
99
|
+
'ENGINE': 'django.db.backends.sqlite3',
|
|
100
|
+
'NAME': BASE_DIR / 'db.sqlite3',
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
# Password validation
|
|
106
|
+
# https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators
|
|
107
|
+
|
|
108
|
+
AUTH_PASSWORD_VALIDATORS = [
|
|
109
|
+
{
|
|
110
|
+
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
|
120
|
+
},
|
|
121
|
+
]
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
# Internationalization
|
|
125
|
+
# https://docs.djangoproject.com/en/5.1/topics/i18n/
|
|
126
|
+
|
|
127
|
+
LANGUAGE_CODE = 'en-us'
|
|
128
|
+
|
|
129
|
+
TIME_ZONE = 'UTC'
|
|
130
|
+
|
|
131
|
+
USE_I18N = True
|
|
132
|
+
|
|
133
|
+
USE_TZ = True
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
# Static files (CSS, JavaScript, Images)
|
|
137
|
+
# https://docs.djangoproject.com/en/5.1/howto/static-files/
|
|
138
|
+
|
|
139
|
+
STATIC_URL = 'static/'
|
|
140
|
+
# STATICFILES_DIRS = [os.path.join(BASE_DIR, "static")]
|
|
141
|
+
|
|
142
|
+
STATICFILES_DIRS = [BASE_DIR / "static"]
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
# Default primary key field type
|
|
146
|
+
# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field
|
|
147
|
+
|
|
148
|
+
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{# components/button.html #}
|
|
2
|
+
<button class="px-4 py-2 rounded bg-blue-500 text-white de hover:bg-blue-600 {{ class }}"
|
|
3
|
+
type="{{ type }}"
|
|
4
|
+
{% if disabled %}disabled{% endif %}
|
|
5
|
+
{{ attributes|safe }}
|
|
6
|
+
>
|
|
7
|
+
{% if icon %}
|
|
8
|
+
{% if icon_position == "left" %}
|
|
9
|
+
<span class="mr-2 text-{{ icon_size }}">
|
|
10
|
+
{% if icon_type == "fa" %}
|
|
11
|
+
<i class="{{ icon }}" {% if icon_color %} style="color: {{ icon_color }};"{% endif %}></i>
|
|
12
|
+
{% elif icon_type == "unicode" %}
|
|
13
|
+
{% if "&#" in icon %}
|
|
14
|
+
{{ icon|safe }}
|
|
15
|
+
{% else %}
|
|
16
|
+
&#{{ icon }};
|
|
17
|
+
{% endif %}
|
|
18
|
+
{% else %}
|
|
19
|
+
{{ icon }}
|
|
20
|
+
{% endif %}
|
|
21
|
+
</span>
|
|
22
|
+
{% endif %}
|
|
23
|
+
{% endif %}
|
|
24
|
+
|
|
25
|
+
{{ label }}
|
|
26
|
+
|
|
27
|
+
{% if icon %}
|
|
28
|
+
{% if icon_position == "right" %}
|
|
29
|
+
<span class="ml-2 text-{{ icon_size }}">
|
|
30
|
+
{% if icon_type == "fa" %}
|
|
31
|
+
<i class="{{ icon }}" {% if icon_color %}style="color: {{ icon_color }};"{% endif %}></i>
|
|
32
|
+
{% elif icon_type == "unicode" %}
|
|
33
|
+
{% if "&#" in icon %}
|
|
34
|
+
{{ icon|safe }}
|
|
35
|
+
{% else %}
|
|
36
|
+
&#{{ icon }};
|
|
37
|
+
{% endif %}
|
|
38
|
+
{% else %}
|
|
39
|
+
{{ icon }}
|
|
40
|
+
{% endif %}
|
|
41
|
+
</span>
|
|
42
|
+
{% endif %}
|
|
43
|
+
{% endif %}
|
|
44
|
+
</button>
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
<button class="px-4 py-2 rounded flex items-center {{ class }}" type="{{ type }}" {% if disabled %}disabled{% endif %}>
|
|
2
|
+
{% if icon %}
|
|
3
|
+
{% if icon_position == "left" %}
|
|
4
|
+
<span class="mr-2 text-{{ icon_size }}">
|
|
5
|
+
{% if icon_type == "fa" %}
|
|
6
|
+
<i class="{{ icon }}" {% if icon_color %}style="color: {{ icon_color }};" {% endif %}></i>
|
|
7
|
+
{% elif icon_type == "unicode" %}
|
|
8
|
+
{% if "&#" in icon %}
|
|
9
|
+
{{ icon|safe }}
|
|
10
|
+
{% else %}
|
|
11
|
+
&#{{ icon }};
|
|
12
|
+
{% endif %}
|
|
13
|
+
{% else %}
|
|
14
|
+
{{ icon }}
|
|
15
|
+
{% endif %}
|
|
16
|
+
</span>
|
|
17
|
+
{% endif %}
|
|
18
|
+
{% endif %}
|
|
19
|
+
|
|
20
|
+
{{ label }}
|
|
21
|
+
|
|
22
|
+
{% if icon %}
|
|
23
|
+
{% if icon_position == "right" %}
|
|
24
|
+
<span class="ml-2 text-{{ icon_size }}">
|
|
25
|
+
{% if icon_type == "fa" %}
|
|
26
|
+
<i class="{{ icon }}" {% if icon_color %}style="color: {{ icon_color }};" {% endif %}></i>
|
|
27
|
+
{% elif icon_type == "unicode" %}
|
|
28
|
+
{% if "&#" in icon %}
|
|
29
|
+
{{ icon|safe }}
|
|
30
|
+
{% else %}
|
|
31
|
+
&#{{ icon }};
|
|
32
|
+
{% endif %}
|
|
33
|
+
{% else %}
|
|
34
|
+
{{ icon }}
|
|
35
|
+
{% endif %}
|
|
36
|
+
</span>
|
|
37
|
+
{% endif %}
|
|
38
|
+
{% endif %}
|
|
39
|
+
</button>
|
|
40
|
+
|
|
41
|
+
<button class="px-4 py-2 rounded flex items-center {{ class }}" type="{{ type }}" {% if disabled %}disabled{% endif %}
|
|
42
|
+
{{ attributes }}>
|
|
43
|
+
{% if icon %}
|
|
44
|
+
{% if icon_position == "left" %}
|
|
45
|
+
<span class="mr-2 text-{{ icon_size }}">
|
|
46
|
+
{% if icon_type == "fa" %}
|
|
47
|
+
<i class="{{ icon }}" {% if icon_color %}style="color: {{ icon_color }};" {% endif %}></i>
|
|
48
|
+
{% elif icon_type == "unicode" %}
|
|
49
|
+
{% if "&#" in icon %}
|
|
50
|
+
{{ icon|safe }}
|
|
51
|
+
{% else %}
|
|
52
|
+
&#{{ icon }};
|
|
53
|
+
{% endif %}
|
|
54
|
+
{% else %}
|
|
55
|
+
{{ icon }}
|
|
56
|
+
{% endif %}
|
|
57
|
+
</span>
|
|
58
|
+
{% endif %}
|
|
59
|
+
{% endif %}
|
|
60
|
+
|
|
61
|
+
{{ label }}
|
|
62
|
+
|
|
63
|
+
{% if icon %}
|
|
64
|
+
{% if icon_position == "right" %}
|
|
65
|
+
<span class="ml-2 text-{{ icon_size }}">
|
|
66
|
+
{% if icon_type == "fa" %}
|
|
67
|
+
<i class="{{ icon }}" {% if icon_color %}style="color: {{ icon_color }};" {% endif %}></i>
|
|
68
|
+
{% elif icon_type == "unicode" %}
|
|
69
|
+
{% if "&#" in icon %}
|
|
70
|
+
{{ icon|safe }}
|
|
71
|
+
{% else %}
|
|
72
|
+
&#{{ icon }};
|
|
73
|
+
{% endif %}
|
|
74
|
+
{% else %}
|
|
75
|
+
{{ icon }}
|
|
76
|
+
{% endif %}
|
|
77
|
+
</span>
|
|
78
|
+
{% endif %}
|
|
79
|
+
{% endif %}
|
|
80
|
+
</button>
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{% load static tailwind_tags %}
|
|
2
|
+
{% load nexui_tags %}
|
|
3
|
+
|
|
4
|
+
<!DOCTYPE html>
|
|
5
|
+
<html lang="en">
|
|
6
|
+
|
|
7
|
+
<head>
|
|
8
|
+
<meta charset="UTF-8"/>
|
|
9
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
|
10
|
+
<title>Formulaire HTMX</title>
|
|
11
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css"
|
|
12
|
+
integrity="sha512-Evv84Mr4kqVGRNSgIGL/F/aIDqQb7xQ2vcrdIwxfjThSH8CSR7PBEakCr51Ck+w+/U6swU2Im1vVX0SVk9ABhg=="
|
|
13
|
+
crossorigin="anonymous" referrerpolicy="no-referrer"/>
|
|
14
|
+
|
|
15
|
+
<script src="{% static 'js/htmx.min.js' %}" defer></script>
|
|
16
|
+
|
|
17
|
+
{% tailwind_css %}
|
|
18
|
+
</head>
|
|
19
|
+
|
|
20
|
+
<body>
|
|
21
|
+
<form id="simple-form">
|
|
22
|
+
<input type="text" name="username" placeholder="Votre nom" required>
|
|
23
|
+
{% button label="Envoyer" type="submit" class="bg-green-500 text-white" %}
|
|
24
|
+
</form>
|
|
25
|
+
|
|
26
|
+
<div id="result"></div>
|
|
27
|
+
|
|
28
|
+
<script>
|
|
29
|
+
document.addEventListener("DOMContentLoaded", function() {
|
|
30
|
+
document.getElementById("simple-form").addEventListener("submit", function(event) {
|
|
31
|
+
event.preventDefault(); // Empêche le rechargement de la page
|
|
32
|
+
|
|
33
|
+
let formData = new FormData(this);
|
|
34
|
+
let username = formData.get("username");
|
|
35
|
+
|
|
36
|
+
if (!username.trim()) {
|
|
37
|
+
alert("Veuillez entrer un nom !");
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
console.log("Nom saisi :", username); // Vérifier si la valeur est bien récupérée
|
|
42
|
+
|
|
43
|
+
// Simulation d'un backend avec un dictionnaire JS
|
|
44
|
+
let fakeBackend = {
|
|
45
|
+
message: `Formulaire soumis avec succès par ${username} !`
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
console.log("Réponse du fake backend :", fakeBackend); // Vérifier la structure des données
|
|
49
|
+
|
|
50
|
+
// Affichage du message dans la div #result
|
|
51
|
+
document.getElementById("result").innerHTML = `<p>${fakeBackend.message}</p>`;
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
</script>
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
</body>
|
|
58
|
+
|
|
59
|
+
</html>
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
{% load static tailwind_tags %}
|
|
2
|
+
{% load nexui_tags %}
|
|
3
|
+
|
|
4
|
+
<!DOCTYPE html>
|
|
5
|
+
<html lang="en">
|
|
6
|
+
|
|
7
|
+
<head>
|
|
8
|
+
<meta charset="UTF-8" />
|
|
9
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
10
|
+
<title>Formulaire HTMX</title>
|
|
11
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css"
|
|
12
|
+
integrity="sha512-Evv84Mr4kqVGRNSgIGL/F/aIDqQb7xQ2vcrdIwxfjThSH8CSR7PBEakCr51Ck+w+/U6swU2Im1vVX0SVk9ABhg=="
|
|
13
|
+
crossorigin="anonymous" referrerpolicy="no-referrer" />
|
|
14
|
+
|
|
15
|
+
<script src="{% static 'js/htmx.min.js' %}" defer></script>
|
|
16
|
+
|
|
17
|
+
{% tailwind_css %}
|
|
18
|
+
</head>
|
|
19
|
+
|
|
20
|
+
<body>
|
|
21
|
+
<div class="mx-2 my-2">
|
|
22
|
+
<form id="simple-form">
|
|
23
|
+
<input type="text" name="username" placeholder="Votre nom" required />
|
|
24
|
+
{% button label="Envoyer" type="submit" class="bg-yellow-500 text-black"%}
|
|
25
|
+
</form>
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<div class="mx-2 my-2">
|
|
29
|
+
<form id="simple-form" hx-post="{% url 'submit-form' %}" hx-target="#result" hx-swap="innerHTML">
|
|
30
|
+
{% csrf_token %}
|
|
31
|
+
<input type="text" name="username" placeholder="Votre nom" required />
|
|
32
|
+
{% button label="Envoyer avec HTMX classique" type="submit" class="bg-green-500 hover:bg-green-300 hover:text-black text-white" %}
|
|
33
|
+
</form>
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
<div class="mx-2 my-2">
|
|
37
|
+
<form id="simple-form" hx-post="{% url 'submit-form' %}" hx-target="#result" hx-swap="innerHTML">
|
|
38
|
+
{% csrf_token %}
|
|
39
|
+
<input type="text" name="username" placeholder="Votre nom" required />
|
|
40
|
+
{% button label="HTMX intégrer" type="submit" class="bg-green-500 hover:bg-green-300 hover:text-black text-white" %}
|
|
41
|
+
</form>
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
<div class="mx-2 my-2">
|
|
45
|
+
<form id="simple-form">
|
|
46
|
+
{% csrf_token %}
|
|
47
|
+
<input type="text" name="username" placeholder="Votre nom" required />
|
|
48
|
+
|
|
49
|
+
{%button label="Dynamique url params" type="submit" class="bg-green-500 text-white" url_name="update-user" url_params="2, tomate" attrs='hx-confirm="Are you okay ?" hx-target="#result" hx-swap="innerHTML"'%}
|
|
50
|
+
</form>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<div id="result"></div>
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
<div class="mx-2 my-2">
|
|
57
|
+
{% button%}
|
|
58
|
+
{%button class='text-yellow-300'%}
|
|
59
|
+
{% button label="Dyn url params" type="submit" class="bg-green-500 text-white" url_name="update-user" url_params="2, tomate" attrs='hx-confirm="Are you okay ?" hx-target="#result" hx-swap="innerHTML"' %}
|
|
60
|
+
|
|
61
|
+
{% button label="Dyn url params 4" type="submit" class="bg-pink-500 hover:bg-pink-300 text-white" url_name="update-user" url_params="4, tomate" attrs="hx-confirm='Are you okay ?' hx-target='#result' hx-swap='innerHTML'" %}
|
|
62
|
+
{% button label="Envoyer" type="submit" class="extra bg-blue-500 text-white px-4 py-2 rounded" attrs='id="submit-button!" title="Cliquez pour envoyer" data-custom="valeur" style="font-weight:bold;"' %}
|
|
63
|
+
{%button label='alerte' attrs='onclick="alert(\'Bouton cliqué!\')"'%}
|
|
64
|
+
|
|
65
|
+
{% button label="Envoyer moi" type="submit" class="bg-green-500 text-white" url_name="update-user" url_params="4, tomate" %}
|
|
66
|
+
|
|
67
|
+
{% button label="Disabled" disabled="true" %}
|
|
68
|
+
{% button label="Télécharger" class="bg-green-500" icon="⬇️" icon_position="left" icon_size="lg" %}
|
|
69
|
+
{% button label="Supprimer" class="bg-red-500" icon="🗑" icon_position="right" %}
|
|
70
|
+
{% button label="Supprimer" class="bg-red-500" icon="😂" icon_position="right" %}
|
|
71
|
+
</div>
|
|
72
|
+
|
|
73
|
+
<div class="mx-2 my-2">
|
|
74
|
+
{% button label="Éditer" icon="fa-solid fa-pen" icon_type="fa" %}
|
|
75
|
+
{% button label="Facebook" icon="fa-brands fa-facebook" icon_color="#FFFFFFFF" icon_type="fa" %}
|
|
76
|
+
{% button label="Facebook" icon="fa-brands fa-facebook-f" icon_color="#FFFFFFFF" icon_type="fa" %}
|
|
77
|
+
|
|
78
|
+
{% button label="Étoile" icon="9733" icon_type="unicode" %}
|
|
79
|
+
{% button label="At Symbol" icon="@" icon_type="unicode" %}
|
|
80
|
+
{# Dans votre template HTML #}
|
|
81
|
+
{% button label="Favori" icon="fa-solid fa-star" icon_type="fa" icon_color="#FFD43B" icon_position='right' class="bg-blue-500" %}
|
|
82
|
+
{% button label="Email" icon="@" icon_type="unicode" icon_position='right' class="bg-yellow-500" %}
|
|
83
|
+
{% button label="Phone" icon="128241" icon_type="unicode" icon_position='right' class="bg-green-500" %}
|
|
84
|
+
{% button label="Phone" icon="9743" icon_type="unicode" icon_position='right' class="bg-green-500" %}
|
|
85
|
+
{% button label="Envoyer" icon="fa-solid fa-paper-plane" icon_type="fa" icon_position='right' class='bg-pink-500 text-green-600' %}
|
|
86
|
+
|
|
87
|
+
</div>
|
|
88
|
+
</body>
|
|
89
|
+
|
|
90
|
+
</html>
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
{% load static tailwind_tags %} {% load nexui_tags %}
|
|
2
|
+
|
|
3
|
+
<!DOCTYPE html>
|
|
4
|
+
<html lang="en">
|
|
5
|
+
<head>
|
|
6
|
+
<meta charset="UTF-8" />
|
|
7
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
8
|
+
<title>Formulaire HTMX</title>
|
|
9
|
+
<link
|
|
10
|
+
rel="stylesheet"
|
|
11
|
+
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css"
|
|
12
|
+
integrity="sha512-Evv84Mr4kqVGRNSgIGL/F/aIDqQb7xQ2vcrdIwxfjThSH8CSR7PBEakCr51Ck+w+/U6swU2Im1vVX0SVk9ABhg=="
|
|
13
|
+
crossorigin="anonymous"
|
|
14
|
+
referrerpolicy="no-referrer"
|
|
15
|
+
/>
|
|
16
|
+
|
|
17
|
+
<script src="{% static 'js/htmx.min.js' %}" defer></script>
|
|
18
|
+
<script src="https://unpkg.com/htmx.org@1.9.2"></script>
|
|
19
|
+
|
|
20
|
+
{% tailwind_css %}
|
|
21
|
+
</head>
|
|
22
|
+
|
|
23
|
+
<body>
|
|
24
|
+
<form id="simple-form">
|
|
25
|
+
<input type="text" name="username" placeholder="Votre nom" required />
|
|
26
|
+
{% button label="Envoyer" type="submit" class="bg-yellow-500 text-black"%}
|
|
27
|
+
</form>
|
|
28
|
+
|
|
29
|
+
<form
|
|
30
|
+
id="simple-form"
|
|
31
|
+
hx-post="{% url 'submit-form' %}"
|
|
32
|
+
hx-target="#result"
|
|
33
|
+
hx-swap="innerHTML"
|
|
34
|
+
>
|
|
35
|
+
{% csrf_token %}
|
|
36
|
+
<input type="text" name="username" placeholder="Votre nom" required />
|
|
37
|
+
{% button label="Envoyer avec HTMX" type="submit" class="bg-green-500 hover:bg-green-300 hover:text-black text-white" %}
|
|
38
|
+
</form>
|
|
39
|
+
|
|
40
|
+
<form
|
|
41
|
+
id="simple-form"
|
|
42
|
+
hx-post="{% url 'submit-form' %}"
|
|
43
|
+
hx-target="#result"
|
|
44
|
+
hx-swap="innerHTML"
|
|
45
|
+
>
|
|
46
|
+
{% csrf_token %}
|
|
47
|
+
<input type="text" name="username" placeholder="Votre nom" required />
|
|
48
|
+
{% button label="Envoyer avec HTMX" type="submit" class="bg-green-500 hover:bg-green-300 hover:text-black text-white" %}
|
|
49
|
+
</form>
|
|
50
|
+
|
|
51
|
+
<form id="simple-form">
|
|
52
|
+
{% csrf_token %}
|
|
53
|
+
<input type="text" name="username" placeholder="Votre nom" required />
|
|
54
|
+
<button
|
|
55
|
+
type="submit"
|
|
56
|
+
class="bg-green-500 text-white"
|
|
57
|
+
hx-post="{% url 'update-user' 1 'mangue' %}"
|
|
58
|
+
hx-target="#result"
|
|
59
|
+
hx-swap="innerHTML"
|
|
60
|
+
hx-confirm="Are you okay ?"
|
|
61
|
+
>
|
|
62
|
+
Dyn URL Params
|
|
63
|
+
</button>
|
|
64
|
+
|
|
65
|
+
{%button label="Dyn url params" type="submit" class="bg-green-500 text-white" url_name="update-user" url_params="2, tomate" attrs='hx-confirm="Are you okay ?" hx-target="#result" hx-swap="innerHTML"'%}
|
|
66
|
+
</form>
|
|
67
|
+
|
|
68
|
+
{% button%} {% button label="Dyn url params" type="submit" class="bg-green-500 text-white" url_name="update-user" url_params="2, tomate" attrs='hx-confirm="Are you okay ?" hx-target="#result" hx-swap="innerHTML"' %}
|
|
69
|
+
|
|
70
|
+
<div id="result"></div>
|
|
71
|
+
|
|
72
|
+
{% button label="Dyn url params 4" type="submit" class="bg-pink-500 hover:bg-pink-300 text-white" url_name="update-user" url_params="4, tomate" attrs="hx-confirm='Are you okay ?' hx-target='#result' hx-swap='innerHTML'" %} {% button label="Envoyer" type="submit" class="extra bg-blue-500 text-white px-4 py-2 rounded" attrs='id="submit-button!" title="Cliquez pour envoyer" data-custom="valeur" style="font-weight:bold;"' %} {%button attrs='onclick="alert(\'Bouton cliqué!\')"'%}
|
|
73
|
+
|
|
74
|
+
{% button label="Envoyer moi" type="submit" class="bg-green-500 text-white" url_name="update-user" url_params="4, tomate" %}
|
|
75
|
+
|
|
76
|
+
{% button
|
|
77
|
+
label="Envoyer mul"
|
|
78
|
+
type="submit"
|
|
79
|
+
class="bg-green-500 text-white"
|
|
80
|
+
url_name="update-user"
|
|
81
|
+
url_params="4, tomate"
|
|
82
|
+
hx-target="#result"
|
|
83
|
+
hx-swap="innerHTML"
|
|
84
|
+
hx-confirm="Êtes-vous sûr ?"
|
|
85
|
+
%}
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
<!-- 🔥 Déplacer le script ici -->
|
|
89
|
+
<script>
|
|
90
|
+
console.log("Script chargé !"); // Vérification
|
|
91
|
+
|
|
92
|
+
document.addEventListener("DOMContentLoaded", function () {
|
|
93
|
+
console.log("DOM prêt !"); // Vérification
|
|
94
|
+
|
|
95
|
+
let form = document.getElementById("simple-form");
|
|
96
|
+
console.log("Form récupéré :", form); // Vérification
|
|
97
|
+
|
|
98
|
+
if (!form) {
|
|
99
|
+
console.error("❌ Erreur : le formulaire n'a pas été trouvé !");
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
form.addEventListener("submit", function (event) {
|
|
104
|
+
event.preventDefault(); // Empêche le rechargement de la page
|
|
105
|
+
console.log("✅ Le formulaire a été soumis !"); // Vérification
|
|
106
|
+
|
|
107
|
+
let formData = new FormData(this);
|
|
108
|
+
let username = formData.get("username");
|
|
109
|
+
|
|
110
|
+
if (!username.trim()) {
|
|
111
|
+
alert("❌ Veuillez entrer un nom !");
|
|
112
|
+
console.log("⚠️ Nom vide, soumission annulée.");
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
console.log("Nom saisi :", username); // Vérifier si la valeur est bien récupérée
|
|
117
|
+
|
|
118
|
+
// Simulation d'un backend avec un dictionnaire JS
|
|
119
|
+
let fakeBackend = {
|
|
120
|
+
message: `Formulaire soumis avec succès par ${username} !`,
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
console.log("Réponse du fake backend :", fakeBackend); // Vérifier la structure des données
|
|
124
|
+
|
|
125
|
+
// Affichage du message dans la div #result
|
|
126
|
+
document.getElementById(
|
|
127
|
+
"result"
|
|
128
|
+
).innerHTML = `<p>${fakeBackend.message}</p>`;
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
</script>
|
|
132
|
+
</body>
|
|
133
|
+
</html>
|
|
134
|
+
<!-- ? fonctionne -->
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
{% load static tailwind_tags %}
|
|
138
|
+
{% load nexui_tags %}
|
|
139
|
+
|
|
140
|
+
<!DOCTYPE html>
|
|
141
|
+
<html lang="en">
|
|
142
|
+
|
|
143
|
+
<head>
|
|
144
|
+
<meta charset="UTF-8" />
|
|
145
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
146
|
+
<title>Mes composants</title>
|
|
147
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css"
|
|
148
|
+
integrity="sha512-Evv84Mr4kqVGRNSgIGL/F/aIDqQb7xQ2vcrdIwxfjThSH8CSR7PBEakCr51Ck+w+/U6swU2Im1vVX0SVk9ABhg=="
|
|
149
|
+
crossorigin="anonymous" referrerpolicy="no-referrer" />
|
|
150
|
+
<script src="{% static 'js/htmx.min.js' %}" defer></script>
|
|
151
|
+
|
|
152
|
+
{% tailwind_css %}
|
|
153
|
+
</head>
|
|
154
|
+
|
|
155
|
+
<body>
|
|
156
|
+
<h1 class="text-red-500">Mes composants</h1>
|
|
157
|
+
|
|
158
|
+
{% button label="Disabled" disabled="true" %}
|
|
159
|
+
{% button label="Télécharger" class="bg-green-500" icon="⬇️" icon_position="left" icon_size="lg" %}
|
|
160
|
+
{% button label="Supprimer" class="bg-red-500" icon="🗑" icon_position="right" %}
|
|
161
|
+
{% button label="Supprimer" class="bg-red-500" icon="😂" icon_position="right" %}
|
|
162
|
+
{% button label="Éditer" icon="fa-solid fa-pen" icon_type="fa" %}
|
|
163
|
+
|
|
164
|
+
{% button label="Facebook" icon="fa-brands fa-facebook" icon_color="#FFFFFFFF" icon_type="fa" %}
|
|
165
|
+
{% button label="Facebook" icon="fa-brands fa-facebook-f" icon_color="#FFFFFFFF" icon_type="fa" %}
|
|
166
|
+
|
|
167
|
+
{% button label="Étoile" icon="9733" icon_type="unicode" %}
|
|
168
|
+
{% button label="At Symbol" icon="@" icon_type="unicode" %}
|
|
169
|
+
{# Dans votre template HTML #}
|
|
170
|
+
{% button label="Favori" icon="fa-solid fa-star" icon_type="fa" icon_color="#FFD43B" class="bg-blue-500" %}
|
|
171
|
+
{% button label="Email" icon="@" icon_type="unicode" class="bg-yellow-500" %}
|
|
172
|
+
{% button label="Phone" icon="128241" icon_type="unicode" class="bg-green-500" %}
|
|
173
|
+
{% button label="Phone" icon="9743" icon_type="unicode" class="bg-green-500" %}
|
|
174
|
+
{% button label="Envoyer" icon="fa-solid fa-paper-plane" icon_type="fa" %}
|
|
175
|
+
|
|
176
|
+
<!-- Bouton avec attributs HTMX -->
|
|
177
|
+
{% button label="Load More" class="bg-purple-500" htmx_get="/load-more" htmx_trigger="click" htmx_target="#content" %}
|
|
178
|
+
{% button label="Update" class="bg-orange-500" htmx_put="/update" htmx_trigger="click" htmx_target="#content" %}
|
|
179
|
+
{% button label="Delete" class="bg-red-500" htmx_delete="/delete" htmx_trigger="click" htmx_target="#content" %}
|
|
180
|
+
</body>
|
|
181
|
+
|
|
182
|
+
</html>
|
|
File without changes
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
from django import template
|
|
2
|
+
from django.urls import reverse
|
|
3
|
+
from django.utils.safestring import mark_safe
|
|
4
|
+
|
|
5
|
+
register = template.Library()
|
|
6
|
+
|
|
7
|
+
@register.inclusion_tag('components/button.html')
|
|
8
|
+
def button(**kwargs):
|
|
9
|
+
context = {
|
|
10
|
+
'label': kwargs.get('label', 'Button'),
|
|
11
|
+
'type': kwargs.get('type', 'button'),
|
|
12
|
+
'class': kwargs.get('class'),
|
|
13
|
+
'icon': kwargs.get('icon'),
|
|
14
|
+
'icon_type': kwargs.get('icon_type', 'emoji'),
|
|
15
|
+
'icon_position': kwargs.get('icon_position', 'left'),
|
|
16
|
+
'icon_size': kwargs.get('icon_size', 'base'),
|
|
17
|
+
'icon_color': kwargs.get('icon_color'),
|
|
18
|
+
'disabled': str(kwargs.get('disabled', False)).lower() in ('true', '1'),
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
# Capture all HTMX-related attributes
|
|
22
|
+
htmx_attrs = []
|
|
23
|
+
|
|
24
|
+
# Construction de l'URL dynamique via reverse
|
|
25
|
+
if 'url_name' in kwargs:
|
|
26
|
+
method = kwargs.get('method', 'post').lower()
|
|
27
|
+
|
|
28
|
+
# Récupérer les paramètres dynamiques de l'URL
|
|
29
|
+
url_params = kwargs.get('url_params', [])
|
|
30
|
+
|
|
31
|
+
# Si les paramètres sont en chaîne de caractères, les convertir en liste
|
|
32
|
+
if isinstance(url_params, str):
|
|
33
|
+
url_params = [p.strip() for p in url_params.split(",")]
|
|
34
|
+
|
|
35
|
+
try:
|
|
36
|
+
url = reverse(kwargs['url_name'], args=url_params)
|
|
37
|
+
htmx_attrs.append(f'hx-{method}="{url}"')
|
|
38
|
+
except Exception as e:
|
|
39
|
+
htmx_attrs.append(f'data-error="URL not found: {e}"')
|
|
40
|
+
|
|
41
|
+
for key, value in kwargs.items():
|
|
42
|
+
if key.startswith('hx-') or key.startswith('data-hx-'):
|
|
43
|
+
htmx_attrs.append(f'{key}="{value}"')
|
|
44
|
+
|
|
45
|
+
# Combine HTMX attributes
|
|
46
|
+
context['attributes'] = mark_safe(' '.join(htmx_attrs))
|
|
47
|
+
|
|
48
|
+
# Add any extra attributes if specified
|
|
49
|
+
if 'attrs' in kwargs:
|
|
50
|
+
context['attributes'] = mark_safe(f"{context['attributes']} {kwargs['attrs']}")
|
|
51
|
+
|
|
52
|
+
return context
|
|
53
|
+
|
|
54
|
+
# from django import template
|
|
55
|
+
# from django.urls import reverse
|
|
56
|
+
# from django.utils.safestring import mark_safe
|
|
57
|
+
|
|
58
|
+
# register = template.Library()
|
|
59
|
+
|
|
60
|
+
# @register.inclusion_tag('components/button.html')
|
|
61
|
+
# def button(**kwargs):
|
|
62
|
+
# context = {
|
|
63
|
+
# 'label': kwargs.get('label', 'Button'),
|
|
64
|
+
# 'type': 'button',
|
|
65
|
+
# 'class': kwargs.get('class', 'bg-blue-500 text-white hover:bg-blue-600'),
|
|
66
|
+
# 'icon': kwargs.get('icon'),
|
|
67
|
+
# 'icon_type': kwargs.get('icon_type', 'emoji'),
|
|
68
|
+
# 'icon_position': kwargs.get('icon_position', 'left'),
|
|
69
|
+
# 'icon_size': kwargs.get('icon_size', 'base'),
|
|
70
|
+
# 'icon_color': kwargs.get('icon_color'),
|
|
71
|
+
# 'disabled': str(kwargs.get('disabled', False)).lower() in ('true', '1'),
|
|
72
|
+
# }
|
|
73
|
+
|
|
74
|
+
# htmx_attrs = []
|
|
75
|
+
|
|
76
|
+
# # Construction de l'URL dynamique via reverse
|
|
77
|
+
# if 'url_name' in kwargs:
|
|
78
|
+
# method = kwargs.get('method', 'post').lower()
|
|
79
|
+
# # Résoudre l'URL dans le backend
|
|
80
|
+
# url = reverse(kwargs['url_name']) # Nous résolvons l'URL ici
|
|
81
|
+
# htmx_attrs.append(f'hx-{method}="{url}"')
|
|
82
|
+
|
|
83
|
+
# # Ajout des autres attributs HTMX
|
|
84
|
+
# if 'target' in kwargs:
|
|
85
|
+
# htmx_attrs.append(f'hx-target="{kwargs["target"]}"')
|
|
86
|
+
# if 'swap' in kwargs:
|
|
87
|
+
# htmx_attrs.append(f'hx-swap="{kwargs["swap"]}"')
|
|
88
|
+
# if 'trigger' in kwargs:
|
|
89
|
+
# htmx_attrs.append(f'hx-trigger="{kwargs["trigger"]}"')
|
|
90
|
+
# if 'indicator' in kwargs:
|
|
91
|
+
# htmx_attrs.append(f'hx-indicator="{kwargs["indicator"]}"')
|
|
92
|
+
# if 'confirm' in kwargs:
|
|
93
|
+
# htmx_attrs.append(f'hx-confirm="{kwargs["confirm"]}"')
|
|
94
|
+
|
|
95
|
+
# # Assemblage des attributs
|
|
96
|
+
# context['attributes'] = mark_safe(' '.join(htmx_attrs))
|
|
97
|
+
|
|
98
|
+
# # Ajout des attributs supplémentaires si spécifiés
|
|
99
|
+
# if 'attrs' in kwargs:
|
|
100
|
+
# context['attributes'] = mark_safe(str(context['attributes']) + ' ' + kwargs['attrs'])
|
|
101
|
+
|
|
102
|
+
# return context
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from django import template
|
|
2
|
+
from django.template.loader import render_to_string
|
|
3
|
+
from django.utils.safestring import mark_safe
|
|
4
|
+
|
|
5
|
+
register = template.Library()
|
|
6
|
+
|
|
7
|
+
@register.inclusion_tag('components/button.html')
|
|
8
|
+
def button(**kwargs):
|
|
9
|
+
context = {
|
|
10
|
+
'label': 'Button',
|
|
11
|
+
'type': 'button',
|
|
12
|
+
'class': 'bg-blue-500 text-white hover:bg-blue-600',
|
|
13
|
+
'icon': None,
|
|
14
|
+
'icon_type': 'emoji', # 'emoji', 'fa', ou 'unicode'
|
|
15
|
+
'icon_position': 'left',
|
|
16
|
+
'icon_size': 'base',
|
|
17
|
+
'icon_color': None, # nouvelle option pour la couleur de l'icône
|
|
18
|
+
'disabled': False,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if kwargs:
|
|
22
|
+
context.update(kwargs)
|
|
23
|
+
|
|
24
|
+
context['disabled'] = str(context['disabled']) in ('true', '1')
|
|
25
|
+
|
|
26
|
+
return context
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
# @register.inclusion_tag('components/button.html')
|
|
31
|
+
# def button(**kwargs):
|
|
32
|
+
# context = {
|
|
33
|
+
# 'label': 'Button',
|
|
34
|
+
# 'type': 'button',
|
|
35
|
+
# 'class': 'bg-blue-500 text-white hover:bg-blue-600',
|
|
36
|
+
# 'icon': None, # Icône par défaut : aucune
|
|
37
|
+
# 'icon_position': 'left', # Position de l’icône
|
|
38
|
+
# 'icon_size': 'base', # Taille de l’icône
|
|
39
|
+
# 'disabled': False, # Bouton désactivé ou non
|
|
40
|
+
# }
|
|
41
|
+
|
|
42
|
+
# if kwargs:
|
|
43
|
+
# context.update(kwargs)
|
|
44
|
+
|
|
45
|
+
# return context
|
|
46
|
+
|
|
47
|
+
# @register.inclusion_tag('components/button.html')
|
|
48
|
+
# def button(**kwargs):
|
|
49
|
+
# context = {
|
|
50
|
+
# 'label': 'Button',
|
|
51
|
+
# 'type': 'button',
|
|
52
|
+
# 'class': 'bg-blue-500 text-white hover:bg-blue-600'
|
|
53
|
+
# }
|
|
54
|
+
|
|
55
|
+
# if kwargs:
|
|
56
|
+
# context.update(kwargs)
|
|
57
|
+
|
|
58
|
+
# return context
|
nexui/urls.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""
|
|
2
|
+
URL configuration for nexui project.
|
|
3
|
+
|
|
4
|
+
The `urlpatterns` list routes URLs to views. For more information please see:
|
|
5
|
+
https://docs.djangoproject.com/en/5.1/topics/http/urls/
|
|
6
|
+
Examples:
|
|
7
|
+
Function views
|
|
8
|
+
1. Add an import: from my_app import views
|
|
9
|
+
2. Add a URL to urlpatterns: path('', views.home, name='home')
|
|
10
|
+
Class-based views
|
|
11
|
+
1. Add an import: from other_app.views import Home
|
|
12
|
+
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
|
|
13
|
+
Including another URLconf
|
|
14
|
+
1. Import the include() function: from django.urls import include, path
|
|
15
|
+
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
|
16
|
+
"""
|
|
17
|
+
from django.contrib import admin
|
|
18
|
+
from django.urls import path, include
|
|
19
|
+
from . import views
|
|
20
|
+
|
|
21
|
+
urlpatterns = [
|
|
22
|
+
path('admin/', admin.site.urls),
|
|
23
|
+
path("__reload__/", include("django_browser_reload.urls")),
|
|
24
|
+
path('', views.index, name='index'),
|
|
25
|
+
path('some-url/', views.htmx_view, name='htmx_view'),
|
|
26
|
+
path('submit-form/', views.submit_form, name='submit-form'),
|
|
27
|
+
path('update-user/<int:id>/<str:fruit>/', views.update_user, name='update-user'),
|
|
28
|
+
|
|
29
|
+
]
|
nexui/views.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from django.http import HttpResponse
|
|
2
|
+
from django.http import JsonResponse
|
|
3
|
+
from django.shortcuts import render
|
|
4
|
+
from django.urls import reverse
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def submit_form(request):
|
|
8
|
+
username = request.POST.get('username')
|
|
9
|
+
if username:
|
|
10
|
+
message = f"Formulaire soumis avec succès par <strong>{username} {id}</strong>!"
|
|
11
|
+
else:
|
|
12
|
+
message = "Nom non fourni."
|
|
13
|
+
return JsonResponse({'message': message})
|
|
14
|
+
|
|
15
|
+
def update_user(request, id,fruit):
|
|
16
|
+
username = request.POST.get('username')
|
|
17
|
+
if username:
|
|
18
|
+
message = f"Formulaire soumis avec succès par <strong>{username} {id}: {fruit}</strong>!"
|
|
19
|
+
else:
|
|
20
|
+
message = "Nom non fourni."
|
|
21
|
+
return JsonResponse({'message': message})
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def index(request):
|
|
25
|
+
return render(request, 'index.html')
|
|
26
|
+
|
|
27
|
+
# Vue Django pour l'URL htmx
|
|
28
|
+
|
|
29
|
+
def htmx_view(request):
|
|
30
|
+
return HttpResponse('<p>Réponse de HTMX</p>', content_type='text/html')
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
nexui/wsgi.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""
|
|
2
|
+
WSGI config for nexui project.
|
|
3
|
+
|
|
4
|
+
It exposes the WSGI callable as a module-level variable named ``application``.
|
|
5
|
+
|
|
6
|
+
For more information on this file, see
|
|
7
|
+
https://docs.djangoproject.com/en/5.1/howto/deployment/wsgi/
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
|
|
12
|
+
from django.core.wsgi import get_wsgi_application
|
|
13
|
+
|
|
14
|
+
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'nexui.settings')
|
|
15
|
+
|
|
16
|
+
application = get_wsgi_application()
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Hugues Codeur
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: nexui
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Bibliothèque de composants UI modernes avec support HTMX optionnel
|
|
5
|
+
Author-email: Hugues Codeur <huguescodeur@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Classifier: Development Status :: 4 - Beta
|
|
8
|
+
Classifier: Framework :: Django
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Requires-Python: >=3.12
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: Django>=5.1
|
|
18
|
+
Requires-Dist: django-tailwind>=3.8.0
|
|
19
|
+
Provides-Extra: htmx
|
|
20
|
+
Requires-Dist: django-htmx>=1.17.2; extra == "htmx"
|
|
21
|
+
|
|
22
|
+
# 🚀 NexUI
|
|
23
|
+
|
|
24
|
+
NexUI est une bibliothèque de composants UI pour Django, optimisée pour HTMX et basée sur Tailwind CSS. Elle permet d'ajouter facilement des éléments interactifs à vos applications Django tout en bénéficiant des avantages d'une intégration fluide avec HTMX pour la gestion des requêtes AJAX.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 📌 Installation
|
|
29
|
+
|
|
30
|
+
### Installation de base
|
|
31
|
+
```bash
|
|
32
|
+
pip install nexui
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Installation avec support HTMX
|
|
36
|
+
Si vous prévoyez d'utiliser HTMX avec vos composants :
|
|
37
|
+
```bash
|
|
38
|
+
pip install nexui[htmx]
|
|
39
|
+
```
|
|
40
|
+
Ou installez HTMX séparément plus tard :
|
|
41
|
+
```bash
|
|
42
|
+
pip install django-htmx
|
|
43
|
+
```
|
|
44
|
+
Ajoutez `nexui` à la liste des applications installées dans `settings.py` :
|
|
45
|
+
```python
|
|
46
|
+
INSTALLED_APPS = [
|
|
47
|
+
...
|
|
48
|
+
'nexui',
|
|
49
|
+
]
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## 🎨 Fonctionnalités
|
|
55
|
+
|
|
56
|
+
✅ Composants UI réutilisables pour Django
|
|
57
|
+
🔥 Intégration fluide avec HTMX
|
|
58
|
+
🎨 Basé sur Tailwind CSS pour un design moderne
|
|
59
|
+
📦 Facile à installer et à utiliser
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## 🚀 Utilisation
|
|
64
|
+
|
|
65
|
+
### Charger les tags NexUI dans vos templates Django
|
|
66
|
+
|
|
67
|
+
```django
|
|
68
|
+
{% load nexui_tags %}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## 📖 Documentation
|
|
74
|
+
|
|
75
|
+
### 🔘 Composant Button
|
|
76
|
+
|
|
77
|
+
Le composant `button` permet de créer des boutons personnalisables avec des icônes et des interactions HTMX.
|
|
78
|
+
|
|
79
|
+
#### **Options disponibles :**
|
|
80
|
+
- `label` : Texte du bouton
|
|
81
|
+
- `type` : Type du bouton (`button`, `submit`, `reset`)
|
|
82
|
+
- `class` : Classes CSS personnalisées
|
|
83
|
+
- `icon` : Icône (supporte Font Awesome et Unicode)
|
|
84
|
+
- `icon_type` : Type d'icône (`fa`, `unicode`, `emoji`)
|
|
85
|
+
- `icon_position` : Position de l'icône (`left`, `right`)
|
|
86
|
+
- `icon_size` : Taille de l'icône
|
|
87
|
+
- `icon_color` : Couleur de l'icône
|
|
88
|
+
- `disabled` : Désactive le bouton (`true`)
|
|
89
|
+
- `url_name` : Nom de l'URL Django
|
|
90
|
+
- `url_params` : Paramètres dynamiques pour l'URL Django
|
|
91
|
+
- `attrs` : Attributs HTML et HTMX supplémentaires (_hx-_*, id, style, data-\* etc.)
|
|
92
|
+
|
|
93
|
+
### **Exemples d'utilisation :**
|
|
94
|
+
|
|
95
|
+
#### 1️⃣ Bouton simple
|
|
96
|
+
```django
|
|
97
|
+
{% button label="Envoyer" %}
|
|
98
|
+
```
|
|
99
|
+
#### 2️⃣ Bouton simple personnalisé
|
|
100
|
+
```django
|
|
101
|
+
{% button label="Envoyer" type="submit" class="bg-yellow-500 text-black" %}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
#### 3️⃣ Bouton avec HTMX
|
|
105
|
+
```django
|
|
106
|
+
{% button label="Envoyer avec HTMX" type="submit" class="bg-green-500" attrs="hx-post='/submit' hx-target='#result' hx-swap='innerHTML'" %}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
#### 4️⃣ Bouton avec URL dynamique
|
|
110
|
+
```django
|
|
111
|
+
{% button label="Dynamique URL Params" type="submit" class="bg-blue-500 text-white" url_name="update-user" url_params="2, tomate" attrs="hx-confirm='Êtes-vous sûr ?' hx-target='#result' hx-swap='innerHTML'" %}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
#### 5️⃣ Bouton avec URL dynamique et un seul paramètres
|
|
115
|
+
```django
|
|
116
|
+
{% button label="Dynamique URL Params" type="submit" class="bg-blue-500 text-white" url_name="update-user" url_params="1" attrs="hx-confirm='Êtes-vous sûr ?' hx-target='#result' hx-swap='innerHTML'" %}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
#### 6️⃣ Bouton avec URL dynamique et plusieurs paramètres
|
|
120
|
+
```django
|
|
121
|
+
{% button label="Dynamique URL Params" type="submit" class="bg-blue-500 text-white" url_name="update-user" url_params="1, developer" attrs="hx-confirm='Êtes-vous sûr ?' hx-target='#result' hx-swap='innerHTML'" %}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
#### 7️⃣ Bouton avec émojis
|
|
126
|
+
```django
|
|
127
|
+
{% button label="Télécharger" class="bg-green-500" icon="⬇️" icon_position="left" icon_size="lg" %}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
#### 8️⃣ Bouton désactivé
|
|
131
|
+
```django
|
|
132
|
+
{% button label="Disabled" disabled="true" %}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
#### 9️⃣ Bouton avec Font Awesome
|
|
136
|
+
```django
|
|
137
|
+
{% button label="Éditer" icon="fa-solid fa-pen" icon_type="fa" %}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
#### 🔟 Bouton avec code HTML
|
|
141
|
+
```django
|
|
142
|
+
{% button label="Étoile" icon="9733" icon_type="unicode" %}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
```django
|
|
146
|
+
{% button label="At Symbol" icon="@" icon_type="unicode" %}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## 💡 Contribuer
|
|
152
|
+
|
|
153
|
+
Actuellement, le projet est en phase de test initial. Nous encourageons les utilisateurs intéressés à donner leur avis sur la bibliothèque.
|
|
154
|
+
|
|
155
|
+
Si vous souhaitez participer à l'évolution de **NexUI** ou si vous avez des suggestions :
|
|
156
|
+
|
|
157
|
+
1. **Forkez le projet** 📌
|
|
158
|
+
2. **Testez les composants et apportez vos retours** 🛠️
|
|
159
|
+
3. **Créez une issue** pour partager vos suggestions ou problèmes ✅
|
|
160
|
+
|
|
161
|
+
Nous ne pouvons pas accepter de contributions directes pour le moment, mais **vos retours sont essentiels** pour l'évolution de NexUI.
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## 🔗 Liens utiles
|
|
166
|
+
|
|
167
|
+
- [Dépôt GitHub](#) 🖥️
|
|
168
|
+
- [Signaler un bug](#) 🐞
|
|
169
|
+
- [HTMX](https://htmx.org/) ⚡
|
|
170
|
+
- [Tailwind CSS](https://tailwindcss.com/) 🎨
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## ⚖️ Licence
|
|
175
|
+
|
|
176
|
+
Ce projet est sous licence **MIT**. Voir le fichier `LICENSE` pour plus de détails.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
nexui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
nexui/asgi.py,sha256=6_GJggTsImdWAkMRa5A2nmgZUXoxy1hB_ZgAiKIp-5k,403
|
|
3
|
+
nexui/settings.py,sha256=KJKHFxMATik1UAMNoEb7r1kxMiB2Abld92_B2GqbIzk,3876
|
|
4
|
+
nexui/urls.py,sha256=3qe6RBIGQGOqHFfZv8gK0y1qbhTt0PH8h9WN1KtRPv8,1134
|
|
5
|
+
nexui/views.py,sha256=T0gjBZqkqdkB9ubxld-g2H7wzC-Y4MmcE6p2bLxXMO0,933
|
|
6
|
+
nexui/wsgi.py,sha256=SiDavvxFFo0mEW6jz5iIQLfeuLRJCb5FwsmlB-rgYdM,403
|
|
7
|
+
nexui/templates/base.html,sha256=7stabYPpe3bW3B5xC36Xl31qWhka-D9OZuUbi2DzKew,186
|
|
8
|
+
nexui/templates/form.html,sha256=74VgXKGcNDl0Z1-a101vhhk_Z28bE9XvCU1FGvbSC3E,1879
|
|
9
|
+
nexui/templates/index.html,sha256=gAwtzH2xEqwQz2tTsESwBjgBI7Jy8UAPH92IF8gcM34,4481
|
|
10
|
+
nexui/templates/index_old_1.html,sha256=Q1RcH1lAWDcS3MxHE6Fqkx3xO_rK8iGSb2jjqem1Lbw,7478
|
|
11
|
+
nexui/templates/result.html,sha256=L6LA-sE4v_9ZIA87ZDGEXQHF7AagCLiu7pZn88LsUwY,51
|
|
12
|
+
nexui/templates/components/button.html,sha256=F7vX0XryiThKorR1fgS6Hs12_1GJlhAOciryZrvMWfg,1564
|
|
13
|
+
nexui/templates/components/button_old_1.html,sha256=Jp7Yk3AqkjONjYANLJeiHmHqDroOcHHH1grluoZLKR8,2140
|
|
14
|
+
nexui/templates/components/card.html,sha256=I7uoCmI2IeFrKh-UQN6of1rBtnog3t4CHULDX0q-YtQ,150
|
|
15
|
+
nexui/templates/components/modal.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
|
+
nexui/templates/components/tabs.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
|
+
nexui/templates/components/toast.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
18
|
+
nexui/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
|
+
nexui/templatetags/nexui_tags.py,sha256=6suGx1JPJDTwD0jwTLD-o-P-y9aDVQ724c83Nk65poE,3856
|
|
20
|
+
nexui/templatetags/nexui_tags_old_1.py,sha256=NMslc7Fuw4wzJO5o9K20AME6PpqwgjFgOku2jk3Z7QM,1650
|
|
21
|
+
nexui/templatetags/__pycache__/__init__.cpython-313.pyc,sha256=NupK3Y1gYpArkP1G8ltkUIobAxgOYcbQJ0mJR8Z5K70,174
|
|
22
|
+
nexui/templatetags/__pycache__/custom_filters.cpython-313.pyc,sha256=X0s7jHQqho5wcUKgLmR16UpFRm-IC3XRPPmj0FcRWaA,685
|
|
23
|
+
nexui/templatetags/__pycache__/custom_tags.cpython-313.pyc,sha256=DpuwGMz9BttkfhqlfTqhP3i0XoFRfmHNr1_jrEZVZN8,698
|
|
24
|
+
nexui/templatetags/__pycache__/nexui_tags.cpython-313.pyc,sha256=t4VziALsTSgEpeRokYUyA4AXBlu4UnTuOi-TBOc25pQ,2689
|
|
25
|
+
nexui/templatetags/__pycache__/nexui_tags_old_1.cpython-313.pyc,sha256=VMqWIDHR-Rv6gsRlUp9Kjap0vWwxQF-niwRNvkV6vcc,1016
|
|
26
|
+
nexui-0.1.0.dist-info/LICENSE,sha256=DbxpUuVZGglmFZYk2nTyLBTIHB3escTnUOj6cqrPxJw,1091
|
|
27
|
+
nexui-0.1.0.dist-info/METADATA,sha256=WtaQv7Ftnv8jU3NDQta7ubFHCmSv4hbs3vbHAAmHHRo,5422
|
|
28
|
+
nexui-0.1.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
29
|
+
nexui-0.1.0.dist-info/top_level.txt,sha256=zOxGlTWEpmkMBT0ypbmwlsQoa3RHyW7gNQJH9oQlLWc,6
|
|
30
|
+
nexui-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
nexui
|