090500
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -9,3 +9,4 @@ docs/_book
|
||||
# TODO: where does this rule come from?
|
||||
test/
|
||||
|
||||
node_modules/
|
||||
|
||||
63
README.md
63
README.md
@@ -1,2 +1,65 @@
|
||||
# vikileo.shop
|
||||
|
||||
## Команды для настройки
|
||||
|
||||
```
|
||||
git clone https://git.fipi.pro/krasi/vikileo-shop.git
|
||||
|
||||
cd project_directory
|
||||
python3 -m venv venv
|
||||
pip3 install -r req.pip
|
||||
|
||||
python .\manage.py makemigrations accounts media comments main
|
||||
python .\manage.py migrate
|
||||
python .\manage.py createsuperuser
|
||||
python .\manage.py runserver
|
||||
```
|
||||
|
||||
## Для запуска tailwindcss
|
||||
|
||||
```
|
||||
npx tailwindcss -i .\staticfiles\src\input.css -o .\staticfiles\src\output.css --watch
|
||||
```
|
||||
|
||||
Отменить миграции:
|
||||
> python manage.py showmigrations
|
||||
|
||||
Отмените миграцию, которая была применена раньше своей зависимости:
|
||||
> python manage.py migrate app_name zero
|
||||
|
||||
Откатите миграции до той, которая вызывает проблему, используя команду:
|
||||
> python manage.py migrate app_name migration_name
|
||||
|
||||
## Ошибки при миграции в apps properties
|
||||
Если модель никак не хочеть бигрировать то нужно удалить из всех моделей
|
||||
|
||||
> history = HistoricalRecords()
|
||||
|
||||
В моделе есть строка после всех from просто перекоменть её
|
||||
|
||||
> History = 1
|
||||
|
||||
После создания БД вернуть обратно
|
||||
|
||||
## Ошибки при добавлении в таблицу
|
||||
|
||||
При добавлении нового поля в таблицу БД можно использовать число 1, если это не время для времени есть следующий параметр.
|
||||
|
||||
> default='2024-04-01T12:00:00Z'
|
||||
# Документация по API
|
||||
|
||||
Проект предоставляет документацию по API с использованием Swagger. Чтобы получить доступ к документации API, выполните следующие действия:
|
||||
|
||||
Откройте веб-браузер и перейдите к следующему адресу:
|
||||
|
||||
```bash
|
||||
/swagger
|
||||
```
|
||||
|
||||
## Состав проекта
|
||||
|
||||
```
|
||||
static
|
||||
└── src
|
||||
└── input.css
|
||||
```
|
||||
@@ -1,3 +1,62 @@
|
||||
import logging
|
||||
from django.contrib import admin
|
||||
from django.contrib.auth.admin import UserAdmin
|
||||
|
||||
# Register your models here.
|
||||
from config.accounts.models import User
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ProfileInline(admin.StackedInline):
|
||||
model = User
|
||||
can_delete = False
|
||||
max_num = 1
|
||||
verbose_name = 'Profile'
|
||||
|
||||
verbose_name_plural = 'Profile'
|
||||
fk_name = 'user'
|
||||
|
||||
|
||||
@admin.register(User)
|
||||
class UserAdmin(UserAdmin):
|
||||
ordering = ('email', )
|
||||
list_display = (
|
||||
'id', 'email', 'is_staff', 'is_superuser', 'is_active', 'date_joined', 'last_updated', 'last_login'
|
||||
)
|
||||
search_fields = ('email',)
|
||||
list_filter = (
|
||||
'is_staff', 'is_superuser', 'is_active',
|
||||
)
|
||||
readonly_fields = (
|
||||
'last_login', 'last_updated', 'date_joined'
|
||||
)
|
||||
list_display_links = ('id', 'email')
|
||||
fieldsets = (
|
||||
(None, {'fields': ('email', 'password')}),
|
||||
('Permissions', {'fields': ('groups', 'user_permissions')}),
|
||||
('Roles', {'fields': ('is_staff', 'is_superuser', 'is_active')}),
|
||||
('Profile', {'fields': (
|
||||
'username', 'first_name', 'last_name', 'gender', 'bio', 'address', 'followers'
|
||||
)}),
|
||||
('Dates', {'fields': ('last_login', 'last_updated', 'date_joined')})
|
||||
)
|
||||
add_fieldsets = (
|
||||
(None, {
|
||||
'classes': ('wide', ),
|
||||
'fields': (
|
||||
'email', 'password1', 'password2'
|
||||
)
|
||||
}),
|
||||
)
|
||||
|
||||
|
||||
"""код что отображает все модели всех apps
|
||||
|
||||
|
||||
models = apps.get_models()
|
||||
for model in models:
|
||||
try:
|
||||
admin.site.register(model)
|
||||
except admin.sites.AlreadyRegistered:
|
||||
pass
|
||||
"""
|
||||
|
||||
@@ -3,4 +3,5 @@ from django.apps import AppConfig
|
||||
|
||||
class AccountsConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'accounts'
|
||||
name = 'config.accounts'
|
||||
verbose_name = 'Управление пользователями'
|
||||
|
||||
46
config/accounts/migrations/0001_initial.py
Normal file
46
config/accounts/migrations/0001_initial.py
Normal file
@@ -0,0 +1,46 @@
|
||||
# Generated by Django 4.2.13 on 2024-05-09 15:55
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('auth', '0012_alter_user_first_name_max_length'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='User',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('password', models.CharField(max_length=128, verbose_name='password')),
|
||||
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
|
||||
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
|
||||
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
|
||||
('first_name', models.CharField(blank=True, max_length=60, null=True, verbose_name='Имя')),
|
||||
('last_name', models.CharField(blank=True, max_length=60, null=True, verbose_name='Фамилия')),
|
||||
('gender', models.CharField(choices=[('n', 'Не указано'), ('m', 'Мужчина'), ('f', 'Женщина')], default='n', max_length=10, verbose_name='Пол')),
|
||||
('email', models.EmailField(max_length=254, unique=True, verbose_name='Email Address')),
|
||||
('username', models.CharField(max_length=60, verbose_name='Ник')),
|
||||
('bio', models.TextField(blank=True, verbose_name='О себе')),
|
||||
('image', models.URLField(blank=True, null=True, verbose_name='Аватар')),
|
||||
('address', models.CharField(blank=True, max_length=255, null=True, verbose_name='Адрес')),
|
||||
('date_joined', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Дата регистрации')),
|
||||
('last_updated', models.DateTimeField(auto_now=True, null=True, verbose_name='Последнее обновление')),
|
||||
('last_login', models.DateTimeField(auto_now=True, null=True, verbose_name='Последняя авторизация')),
|
||||
('status', models.BooleanField(default=False, verbose_name='Статус')),
|
||||
('followers', models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL, verbose_name='Подписчики')),
|
||||
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),
|
||||
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'user',
|
||||
'verbose_name_plural': 'users',
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -9,6 +9,7 @@ STATICFILES_DIR = os.path.join(BASE_DIR, "staticfiles")
|
||||
STATIC_DIR = os.path.join(BASE_DIR, "static")
|
||||
MEDIA_DIR = os.path.join(BASE_DIR, "mediafiles")
|
||||
LOGS_DIR = os.path.join(BASE_DIR, "logs")
|
||||
COMPRESS_ROOT = os.path.join(BASE_DIR, "staticfiles")
|
||||
SECRET_KEY = 'django-insecure-xvn9xig-%a4=4xt14#yo6on@g(l$tc!r^8i#ard1nio(4i_b+@'
|
||||
DADATA_API_KEY = 'a6370792e9cfc9afdf5074c604eadf093ce9521f'
|
||||
DEBUG = True
|
||||
|
||||
@@ -14,6 +14,7 @@ from .local_settings import (
|
||||
STATIC_DIR,
|
||||
MEDIA_DIR,
|
||||
LOGS_DIR,
|
||||
COMPRESS_ROOT,
|
||||
CORS_ORIGIN_WHITELIST,
|
||||
CSRF_TRUSTED_ORIGINS
|
||||
)
|
||||
@@ -57,13 +58,14 @@ THIRD_PARTY_APPS = [
|
||||
'autoslug',
|
||||
'localflavor',
|
||||
'simple_history',
|
||||
'compressor',
|
||||
]
|
||||
# Внутренние приложения
|
||||
LOCAL_APPS = [
|
||||
'config.accounts.apps.AccountsConfig',
|
||||
#'system.media.apps.MediaConfig',
|
||||
#'system.comments.apps.CommentsConfig',
|
||||
#'main.apps.MainConfig',
|
||||
'system.media.apps.MediaConfig',
|
||||
'system.comments.apps.CommentsConfig',
|
||||
'main.apps.MainConfig',
|
||||
#'articles.apps.ArticlesConfig',
|
||||
#'todos.apps.TodosConfig',
|
||||
]
|
||||
@@ -167,4 +169,7 @@ CSRF_TRUSTED_ORIGINS = CSRF_TRUSTED_ORIGINS
|
||||
CSRF_COOKIE_SECURE = True
|
||||
CSRF_COOKIE_HTTPONLY = True
|
||||
# При выходе из учётной записи вас направит на данный url
|
||||
LOGOUT_REDIRECT_URL = "main"
|
||||
LOGOUT_REDIRECT_URL = "main"
|
||||
COMPRESS_ROOT = COMPRESS_ROOT
|
||||
COMPRESS_ENABLED = True
|
||||
STATICFILES_FINDERS = ('compressor.finders.CompressorFinder',)
|
||||
@@ -5,9 +5,11 @@ from django.conf.urls.static import static
|
||||
from rest_framework import permissions
|
||||
from drf_yasg.views import get_schema_view
|
||||
from drf_yasg import openapi
|
||||
#from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView, TokenVerifyView
|
||||
# Вставки из апсов приложения
|
||||
# Машиночитаемая [схема] описывает, какие ресурсы доступны через API
|
||||
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView, TokenVerifyView
|
||||
"""
|
||||
Вставки из апсов приложения
|
||||
Машиночитаемая [схема] описывает, какие ресурсы доступны через API
|
||||
"""
|
||||
schema_view = get_schema_view(
|
||||
openapi.Info(
|
||||
title="vikileo.shop API",
|
||||
@@ -17,35 +19,39 @@ schema_view = get_schema_view(
|
||||
public=True,
|
||||
permission_classes=(permissions.AllowAny,),
|
||||
)
|
||||
# Префикс для понтов, можно без него но сним проще ориентироваться что должно иди на фронт, а что для тестов.
|
||||
""" Префикс для понтов, можно без него но сним проще ориентироваться что должно иди на фронт, а что для тестов. """
|
||||
api_prefix = 'api'
|
||||
# Кортежи адресов для системных приложений
|
||||
""" Кортежи адресов для системных приложений """
|
||||
urlpatterns_system = [
|
||||
path('admin/', admin.site.urls),# Адрес админ панели
|
||||
path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-redoc'), # API сборник адресов
|
||||
path('admin/', admin.site.urls), # Адрес админ панели
|
||||
path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-redoc'), # API сборник адресов
|
||||
path('api-rest/', include('rest_framework.urls')), # API rest, допилить виюшку
|
||||
path(f'{api_prefix}/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'), # Присвоение токена
|
||||
path(f'{api_prefix}/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'), # Перевыдача токена
|
||||
path(f'{api_prefix}/token/verify/', TokenVerifyView.as_view(), name='token_verify'), # Верифекация токена
|
||||
]
|
||||
# Кортежи адресов для приложений
|
||||
""" Кортежи адресов для приложений """
|
||||
urlpatterns_apps = [
|
||||
path('', include('main.urls')), # Адрес главной странице (заглушка)
|
||||
path(f'{api_prefix}/', include('config.accounts.urls')), # Адрес управление учётными данными
|
||||
#path(f'{api_prefix}/', include('system.comments.urls')), # Адрес комментариев от пользователей
|
||||
#path(f'{api_prefix}/', include('todos.urls')), # Адрес статей
|
||||
#path(f'{api_prefix}/', include('articles.urls')), # Адрес стадей для пользователей
|
||||
path(f'{api_prefix}/', include('system.comments.urls')), # Адрес комментариев от пользователей
|
||||
path('', include('main.urls')), # Адрес главной странице (заглушка)
|
||||
path('', include('config.accounts.urls')), # Адрес управление учётными данными
|
||||
|
||||
]
|
||||
# Кортежи адресов для тестовых приложений
|
||||
""" Кортежи адресов для тестовых приложений """
|
||||
urlpatterns_test = [
|
||||
#path('/accounts/', include('system.accounts.urls')), # Адрес управление учётными данными
|
||||
#path(f'{api_prefix}/', include('system.media.urls')), # Адрес файлаобменника
|
||||
#path(f'{api_prefix}/', include('todos.urls')), # Адрес задач админов
|
||||
#path(f'{api_prefix}/', include('articles.urls')), # Адрес стадей для пользователей
|
||||
#path(f'{api_prefix}/token/', obtain_token, name='token_obtain_pair'),
|
||||
#path(f'{api_prefix}/protected/', protected_view, name='protected_view'),
|
||||
path('api-rest/', include('rest_framework.urls')), # API rest, допилить виюшку
|
||||
#path(f'{api_prefix}/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'), # Присвоение токена
|
||||
#path(f'{api_prefix}/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'), # Перевыдача токена
|
||||
#path(f'{api_prefix}/token/verify/', TokenVerifyView.as_view(), name='token_verify'), # Верифекация токена
|
||||
#path(f'{api_prefix}/', include('system.media.urls')), # Адрес файлаобменника
|
||||
]
|
||||
# Объединение кортежа адресов
|
||||
""" Объединение кортежа адресов """
|
||||
urlpatterns = urlpatterns_system + urlpatterns_apps + urlpatterns_test
|
||||
# Обслуживание файлов, загруженных пользователем во время разработки
|
||||
""" Обслуживание файлов, загруженных пользователем во время разработки """
|
||||
if settings.DEBUG:
|
||||
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
||||
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
||||
|
||||
|
||||
|
||||
|
||||
BIN
db.sqlite3
Normal file
BIN
db.sqlite3
Normal file
Binary file not shown.
0
main/__init__.py
Normal file
0
main/__init__.py
Normal file
3
main/admin.py
Normal file
3
main/admin.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
6
main/apps.py
Normal file
6
main/apps.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class MainConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'main'
|
||||
0
main/context_processors.py
Normal file
0
main/context_processors.py
Normal file
29
main/migrations/0001_initial.py
Normal file
29
main/migrations/0001_initial.py
Normal file
@@ -0,0 +1,29 @@
|
||||
# Generated by Django 4.2.13 on 2024-05-09 19:08
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='ThemeConfiguration',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('theme', models.BooleanField(default=True, verbose_name='theme')),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='themeconfiguration',
|
||||
constraint=models.UniqueConstraint(fields=('user',), name='One Entry Per User'),
|
||||
),
|
||||
]
|
||||
16
main/migrations/0002_delete_themeconfiguration.py
Normal file
16
main/migrations/0002_delete_themeconfiguration.py
Normal file
@@ -0,0 +1,16 @@
|
||||
# Generated by Django 4.2.13 on 2024-05-09 19:13
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('main', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.DeleteModel(
|
||||
name='ThemeConfiguration',
|
||||
),
|
||||
]
|
||||
0
main/migrations/__init__.py
Normal file
0
main/migrations/__init__.py
Normal file
1
main/models.py
Normal file
1
main/models.py
Normal file
@@ -0,0 +1 @@
|
||||
from django.db import models
|
||||
3
main/tests.py
Normal file
3
main/tests.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
13
main/urls.py
Normal file
13
main/urls.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from django.urls import path, include
|
||||
from rest_framework.routers import DefaultRouter
|
||||
#
|
||||
from main import views
|
||||
from .views import MainView
|
||||
#
|
||||
#main_router = DefaultRouter(trailing_slash=False)
|
||||
#main_router.register('main', views.MainView)
|
||||
#
|
||||
urlpatterns = [
|
||||
path('', MainView.as_view(), name='main'),
|
||||
#path('', include(main_router.urls)),
|
||||
]
|
||||
14
main/views.py
Normal file
14
main/views.py
Normal file
@@ -0,0 +1,14 @@
|
||||
from django.shortcuts import render
|
||||
from django.views.generic import View, TemplateView
|
||||
|
||||
|
||||
# Простое отображение страницы заглушки.
|
||||
class MainView(TemplateView):
|
||||
template_name = 'index.html'
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
context = {
|
||||
'title': 'Объявления',
|
||||
"message_hello": "Тут какой-то мессадж."
|
||||
}
|
||||
return render(request, 'index.html', context)
|
||||
1358
package-lock.json
generated
Normal file
1358
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
15
package.json
Normal file
15
package.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"scripts": {
|
||||
"dev": "npx tailwindcss -i .\\staticfiles\\src\\input.css -o .\\staticfiles\\src\\output.css --watch\n",
|
||||
"build": "npx tailwindcss -i ./static/src/input.css -o ./static/src/styles.css -m"
|
||||
},
|
||||
"devDependencies": {
|
||||
"tailwindcss": "^3.4.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tailwindcss/aspect-ratio": "^0.4.2",
|
||||
"@tailwindcss/forms": "^0.5.7",
|
||||
"@tailwindcss/typography": "^0.5.13",
|
||||
"flowbite": "^2.3.0"
|
||||
}
|
||||
}
|
||||
1
static/staticfiles.json
Normal file
1
static/staticfiles.json
Normal file
@@ -0,0 +1 @@
|
||||
{"paths": {}, "version": "1.1", "hash": "d75171398898"}
|
||||
1
staticfiles/CACHE/css/output.06b63291a015.css
Normal file
1
staticfiles/CACHE/css/output.06b63291a015.css
Normal file
File diff suppressed because one or more lines are too long
1
staticfiles/CACHE/css/output.19e6422dab61.css
Normal file
1
staticfiles/CACHE/css/output.19e6422dab61.css
Normal file
File diff suppressed because one or more lines are too long
1
staticfiles/CACHE/css/output.19fc61a5f6ac.css
Normal file
1
staticfiles/CACHE/css/output.19fc61a5f6ac.css
Normal file
File diff suppressed because one or more lines are too long
1
staticfiles/CACHE/css/output.32a8df5af0be.css
Normal file
1
staticfiles/CACHE/css/output.32a8df5af0be.css
Normal file
File diff suppressed because one or more lines are too long
1
staticfiles/CACHE/css/output.38daa0cd5a1a.css
Normal file
1
staticfiles/CACHE/css/output.38daa0cd5a1a.css
Normal file
File diff suppressed because one or more lines are too long
1
staticfiles/CACHE/css/output.3d70318c7b8c.css
Normal file
1
staticfiles/CACHE/css/output.3d70318c7b8c.css
Normal file
File diff suppressed because one or more lines are too long
1
staticfiles/CACHE/css/output.3e4256da6589.css
Normal file
1
staticfiles/CACHE/css/output.3e4256da6589.css
Normal file
File diff suppressed because one or more lines are too long
1
staticfiles/CACHE/css/output.a455525860f1.css
Normal file
1
staticfiles/CACHE/css/output.a455525860f1.css
Normal file
File diff suppressed because one or more lines are too long
1
staticfiles/CACHE/css/output.a535c6c01d52.css
Normal file
1
staticfiles/CACHE/css/output.a535c6c01d52.css
Normal file
File diff suppressed because one or more lines are too long
1
staticfiles/CACHE/css/output.b041454cdfd5.css
Normal file
1
staticfiles/CACHE/css/output.b041454cdfd5.css
Normal file
File diff suppressed because one or more lines are too long
1
staticfiles/CACHE/css/output.dbdb7cee0813.css
Normal file
1
staticfiles/CACHE/css/output.dbdb7cee0813.css
Normal file
File diff suppressed because one or more lines are too long
1
staticfiles/CACHE/css/output.e69458ba9287.css
Normal file
1
staticfiles/CACHE/css/output.e69458ba9287.css
Normal file
File diff suppressed because one or more lines are too long
BIN
staticfiles/img/logo.jpg
Normal file
BIN
staticfiles/img/logo.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 38 KiB |
BIN
staticfiles/img/logo.png
Normal file
BIN
staticfiles/img/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 82 KiB |
BIN
staticfiles/img/Без имени-1.psd
Normal file
BIN
staticfiles/img/Без имени-1.psd
Normal file
Binary file not shown.
3
staticfiles/src/input.css
Normal file
3
staticfiles/src/input.css
Normal file
@@ -0,0 +1,3 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
2461
staticfiles/src/output.css
Normal file
2461
staticfiles/src/output.css
Normal file
File diff suppressed because it is too large
Load Diff
0
system/__init__.py
Normal file
0
system/__init__.py
Normal file
0
system/comments/__init__.py
Normal file
0
system/comments/__init__.py
Normal file
5
system/comments/admin.py
Normal file
5
system/comments/admin.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from django.contrib import admin
|
||||
from simple_history.admin import SimpleHistoryAdmin
|
||||
from .models import *
|
||||
|
||||
admin.site.register(Comment, SimpleHistoryAdmin)
|
||||
7
system/comments/apps.py
Normal file
7
system/comments/apps.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class CommentsConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'system.comments'
|
||||
verbose_name = 'Комментарии'
|
||||
32
system/comments/migrations/0001_initial.py
Normal file
32
system/comments/migrations/0001_initial.py
Normal file
@@ -0,0 +1,32 @@
|
||||
# Generated by Django 4.2.13 on 2024-05-09 16:30
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Comment',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('content', models.TextField(help_text='Введите комментарий', verbose_name='Комментарий')),
|
||||
('created', models.DateTimeField(auto_now_add=True)),
|
||||
('updated', models.DateTimeField(auto_now=True)),
|
||||
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Комментарий',
|
||||
'verbose_name_plural': 'Комментарии',
|
||||
'ordering': ['-created'],
|
||||
},
|
||||
),
|
||||
]
|
||||
0
system/comments/migrations/__init__.py
Normal file
0
system/comments/migrations/__init__.py
Normal file
17
system/comments/models.py
Normal file
17
system/comments/models.py
Normal file
@@ -0,0 +1,17 @@
|
||||
from django.db import models
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
""" Комментарии основная модель """
|
||||
|
||||
|
||||
class Comment(models.Model):
|
||||
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
|
||||
content = models.TextField(verbose_name='Комментарий', help_text='Введите комментарий')
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
updated = models.DateTimeField(auto_now=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'Комментарий'
|
||||
verbose_name_plural = 'Комментарии'
|
||||
ordering = ['-created']
|
||||
48
system/comments/serializers.py
Normal file
48
system/comments/serializers.py
Normal file
@@ -0,0 +1,48 @@
|
||||
from rest_framework import serializers
|
||||
from django.contrib.auth import get_user_model
|
||||
|
||||
from system.comments.models import Comment
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class AuthorSerializer(serializers.ModelSerializer):
|
||||
following = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ('username', 'bio', 'image', 'following')
|
||||
ref_name = 'GoodsAuthorSerializer' # Указываем уникальное имя для этого сериализатора
|
||||
|
||||
def get_following(self, obj):
|
||||
user = self.context.get('request').user
|
||||
if user.is_authenticated:
|
||||
return obj.followers.filter(pk=user.id).exists()
|
||||
return False
|
||||
|
||||
|
||||
class CommentSerializer(serializers.ModelSerializer):
|
||||
author = serializers.SerializerMethodField()
|
||||
createdAt = serializers.DateTimeField(source='created', format='%Y-%m-%dT%H:%M:%S.%fZ', required=False)
|
||||
updatedAt = serializers.DateTimeField(source='updated', format='%Y-%m-%dT%H:%M:%S.%fZ', required=False)
|
||||
body = serializers.CharField(source='content', required=True)
|
||||
|
||||
|
||||
class Meta:
|
||||
model = Comment
|
||||
fields = ['id', 'createdAt', 'updatedAt', 'body', 'author']
|
||||
|
||||
|
||||
def get_author(self, obj):
|
||||
request = self.context.get('request')
|
||||
serializer = AuthorSerializer(obj.author, context={'request': request})
|
||||
return serializer.data
|
||||
|
||||
def create(self, validated_data):
|
||||
comment = Comment(
|
||||
**validated_data,
|
||||
author=self.context['request'].user,
|
||||
article=self.context['article']
|
||||
)
|
||||
comment.save()
|
||||
return comment
|
||||
8
system/comments/urls.py
Normal file
8
system/comments/urls.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from django.urls import path
|
||||
|
||||
from system.comments import views
|
||||
|
||||
urlpatterns = [
|
||||
#path('articles/<str:slug>/comments', views.CommentView.as_view(), name='comment-article'),
|
||||
#path('articles/<str:slug>/comments/<int:id>', views.DeleteCommentView.as_view(), name='comment-delete'),
|
||||
]
|
||||
85
system/comments/views.py
Normal file
85
system/comments/views.py
Normal file
@@ -0,0 +1,85 @@
|
||||
from rest_framework import generics , status
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.permissions import IsAuthenticated, IsAuthenticatedOrReadOnly
|
||||
from rest_framework.response import Response
|
||||
|
||||
from system.comments.models import Comment
|
||||
from system.comments.serializers import CommentSerializer
|
||||
|
||||
|
||||
"""class CommentView(generics.ListCreateAPIView):
|
||||
queryset = Comment.objects.all()
|
||||
serializer_class = CommentSerializer
|
||||
permission_classes=[IsAuthenticated,]
|
||||
|
||||
def get_permissions(self):
|
||||
if self.request.method == 'GET':
|
||||
return [IsAuthenticatedOrReadOnly()]
|
||||
return super().get_permissions()
|
||||
|
||||
|
||||
def post(self, request, slug, *args, **kwargs):
|
||||
try:
|
||||
|
||||
article = Article.objects.get(slug=slug)
|
||||
comment_data = request.data.get('comment')
|
||||
|
||||
serializer_context = self.get_serializer_context()
|
||||
serializer_context['article'] = article
|
||||
|
||||
serializer = self.get_serializer(data=comment_data, context=serializer_context)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
self.perform_create(serializer)
|
||||
|
||||
return Response({"comment": serializer.data}, status=status.HTTP_200_OK)
|
||||
|
||||
except Exception:
|
||||
return Response({"errors": {
|
||||
"body": [
|
||||
"Bad Request"
|
||||
]
|
||||
}}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
|
||||
|
||||
def list(self, request, slug, *args, **kwargs):
|
||||
try:
|
||||
|
||||
article = Article.objects.get(slug=slug)
|
||||
comments = Comment.objects.filter(article=article).order_by('-created')
|
||||
|
||||
serializer = self.get_serializer(comments, many=True)
|
||||
|
||||
response = {
|
||||
'comments': serializer.data,
|
||||
}
|
||||
|
||||
return Response(response)
|
||||
|
||||
except Exception:
|
||||
return Response({"errors": {
|
||||
"body": [
|
||||
"Bad Request"
|
||||
]
|
||||
}}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
|
||||
class DeleteCommentView(generics.DestroyAPIView):
|
||||
|
||||
def destroy(self, request, slug, id, *args, **kwargs):
|
||||
try:
|
||||
|
||||
Article.objects.get(slug=slug)
|
||||
comment = Comment.objects.get(id=id)
|
||||
self.perform_destroy(comment)
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
except Exception:
|
||||
return Response({"errors": {
|
||||
"body": [
|
||||
"Bad Request"
|
||||
]
|
||||
}}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
"""
|
||||
|
||||
0
system/media/__init__.py
Normal file
0
system/media/__init__.py
Normal file
7
system/media/admin.py
Normal file
7
system/media/admin.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from django.contrib import admin
|
||||
from simple_history.admin import SimpleHistoryAdmin
|
||||
from .models import *
|
||||
|
||||
admin.site.register(Images, SimpleHistoryAdmin)
|
||||
admin.site.register(Videos, SimpleHistoryAdmin)
|
||||
admin.site.register(OtherFiles, SimpleHistoryAdmin)
|
||||
7
system/media/apps.py
Normal file
7
system/media/apps.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class MediaConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'system.media'
|
||||
verbose_name = 'Файловое хранилище'
|
||||
136
system/media/migrations/0001_initial.py
Normal file
136
system/media/migrations/0001_initial.py
Normal file
@@ -0,0 +1,136 @@
|
||||
# Generated by Django 4.2.13 on 2024-05-09 16:30
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import simple_history.models
|
||||
import system.media.validators
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Videos',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Дата обновления')),
|
||||
('file_name', models.CharField(help_text='Введите имя файла', max_length=255, verbose_name='Имя файла')),
|
||||
('file', models.FileField(help_text='Загрузите видео', upload_to='videos/%Y/%m/%d/', validators=[system.media.validators.validate_max_file_size], verbose_name='Видео')),
|
||||
('author', models.ForeignKey(help_text='Выберите автора объекта', null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='Автор')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Видео',
|
||||
'verbose_name_plural': 'Видео',
|
||||
'ordering': ['-created_at'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='OtherFiles',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Дата обновления')),
|
||||
('file_name', models.CharField(help_text='Введите имя файла', max_length=255, verbose_name='Имя файла')),
|
||||
('file', models.FileField(help_text='Загрузите документ', upload_to='documents/%Y/%m/%d/', validators=[system.media.validators.validate_max_file_size], verbose_name='Документ')),
|
||||
('author', models.ForeignKey(help_text='Выберите автора объекта', null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='Автор')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Документ',
|
||||
'verbose_name_plural': 'Документы',
|
||||
'ordering': ['-created_at'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Images',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Дата обновления')),
|
||||
('file_name', models.CharField(help_text='Введите имя файла', max_length=255, verbose_name='Имя файла')),
|
||||
('file', models.ImageField(help_text='Загрузите изображение', upload_to='images/%Y/%m/%d/', validators=[system.media.validators.validate_max_file_size], verbose_name='Изображение')),
|
||||
('author', models.ForeignKey(help_text='Выберите автора объекта', null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='Автор')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Изображение',
|
||||
'verbose_name_plural': 'Изображения',
|
||||
'ordering': ['-created_at'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='HistoricalVideos',
|
||||
fields=[
|
||||
('id', models.BigIntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
|
||||
('created_at', models.DateTimeField(blank=True, editable=False, verbose_name='Дата создания')),
|
||||
('updated_at', models.DateTimeField(blank=True, editable=False, verbose_name='Дата обновления')),
|
||||
('file_name', models.CharField(help_text='Введите имя файла', max_length=255, verbose_name='Имя файла')),
|
||||
('file', models.TextField(help_text='Загрузите видео', max_length=100, validators=[system.media.validators.validate_max_file_size], verbose_name='Видео')),
|
||||
('history_id', models.AutoField(primary_key=True, serialize=False)),
|
||||
('history_date', models.DateTimeField(db_index=True)),
|
||||
('history_change_reason', models.CharField(max_length=100, null=True)),
|
||||
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
|
||||
('author', models.ForeignKey(blank=True, db_constraint=False, help_text='Выберите автора объекта', null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Автор')),
|
||||
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'historical Видео',
|
||||
'verbose_name_plural': 'historical Видео',
|
||||
'ordering': ('-history_date', '-history_id'),
|
||||
'get_latest_by': ('history_date', 'history_id'),
|
||||
},
|
||||
bases=(simple_history.models.HistoricalChanges, models.Model),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='HistoricalOtherFiles',
|
||||
fields=[
|
||||
('id', models.BigIntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
|
||||
('created_at', models.DateTimeField(blank=True, editable=False, verbose_name='Дата создания')),
|
||||
('updated_at', models.DateTimeField(blank=True, editable=False, verbose_name='Дата обновления')),
|
||||
('file_name', models.CharField(help_text='Введите имя файла', max_length=255, verbose_name='Имя файла')),
|
||||
('file', models.TextField(help_text='Загрузите документ', max_length=100, validators=[system.media.validators.validate_max_file_size], verbose_name='Документ')),
|
||||
('history_id', models.AutoField(primary_key=True, serialize=False)),
|
||||
('history_date', models.DateTimeField(db_index=True)),
|
||||
('history_change_reason', models.CharField(max_length=100, null=True)),
|
||||
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
|
||||
('author', models.ForeignKey(blank=True, db_constraint=False, help_text='Выберите автора объекта', null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Автор')),
|
||||
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'historical Документ',
|
||||
'verbose_name_plural': 'historical Документы',
|
||||
'ordering': ('-history_date', '-history_id'),
|
||||
'get_latest_by': ('history_date', 'history_id'),
|
||||
},
|
||||
bases=(simple_history.models.HistoricalChanges, models.Model),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='HistoricalImages',
|
||||
fields=[
|
||||
('id', models.BigIntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
|
||||
('created_at', models.DateTimeField(blank=True, editable=False, verbose_name='Дата создания')),
|
||||
('updated_at', models.DateTimeField(blank=True, editable=False, verbose_name='Дата обновления')),
|
||||
('file_name', models.CharField(help_text='Введите имя файла', max_length=255, verbose_name='Имя файла')),
|
||||
('file', models.TextField(help_text='Загрузите изображение', max_length=100, validators=[system.media.validators.validate_max_file_size], verbose_name='Изображение')),
|
||||
('history_id', models.AutoField(primary_key=True, serialize=False)),
|
||||
('history_date', models.DateTimeField(db_index=True)),
|
||||
('history_change_reason', models.CharField(max_length=100, null=True)),
|
||||
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
|
||||
('author', models.ForeignKey(blank=True, db_constraint=False, help_text='Выберите автора объекта', null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Автор')),
|
||||
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'historical Изображение',
|
||||
'verbose_name_plural': 'historical Изображения',
|
||||
'ordering': ('-history_date', '-history_id'),
|
||||
'get_latest_by': ('history_date', 'history_id'),
|
||||
},
|
||||
bases=(simple_history.models.HistoricalChanges, models.Model),
|
||||
),
|
||||
]
|
||||
0
system/media/migrations/__init__.py
Normal file
0
system/media/migrations/__init__.py
Normal file
115
system/media/models.py
Normal file
115
system/media/models.py
Normal file
@@ -0,0 +1,115 @@
|
||||
import os
|
||||
from django.utils import timezone
|
||||
from django.db import models
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.core.exceptions import ValidationError
|
||||
from simple_history.models import HistoricalRecords
|
||||
from django.utils.translation import gettext as _
|
||||
#
|
||||
from .validators import validate_max_file_size
|
||||
#
|
||||
User = get_user_model()
|
||||
#
|
||||
|
||||
|
||||
""" Абстрактная базовая модель для добавления автора полей времени создания и изменения."""
|
||||
|
||||
|
||||
class TimeStampedModel(models.Model):
|
||||
created_at = models.DateTimeField(auto_now_add=True, verbose_name='Дата создания')
|
||||
updated_at = models.DateTimeField(auto_now=True, verbose_name='Дата обновления')
|
||||
author = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, verbose_name='Автор',
|
||||
help_text='Выберите автора объекта')
|
||||
file_name = models.CharField(max_length=255, verbose_name='Имя файла', help_text='Введите имя файла')
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.pk: # Проверяем, что это новый объект (не обновление)
|
||||
self.created_at = timezone.now() # Автоматически устанавливаем дату создания
|
||||
self.updated_at = timezone.now() # Всегда обновляем дату обновления
|
||||
super().save(*args, **kwargs) # Вызываем оригинальный метод сохранения
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.__class__.__name__}: {self.file_name}'
|
||||
|
||||
def generate_file_url(self):
|
||||
if self.file_name:
|
||||
return os.path.join('media', str(self.file_name))
|
||||
|
||||
|
||||
""" Модель файлов изображения """
|
||||
|
||||
|
||||
class Images(TimeStampedModel):
|
||||
file = models.ImageField(upload_to='images/%Y/%m/%d/', verbose_name='Изображение',
|
||||
help_text='Загрузите изображение', validators=[validate_max_file_size])
|
||||
|
||||
history = HistoricalRecords()
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
self.name = f'Image_{self.file_name}' # Префикс "Image_" для изображений
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'Изображение'
|
||||
verbose_name_plural = 'Изображения'
|
||||
ordering = ['-created_at']
|
||||
|
||||
def clean(self):
|
||||
super().clean()
|
||||
if self.file:
|
||||
# Проверяем расширение файла
|
||||
ext = self.file.name.split('.')[-1]
|
||||
if ext.lower() not in ['jpg', 'jpeg', 'png', 'gif']:
|
||||
raise ValidationError(_(
|
||||
'Недопустимый формат изображения. Поддерживаемые форматы: JPG, JPEG, PNG, GIF.'
|
||||
))
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.__class__.__name__}: {self.file_name}'
|
||||
|
||||
|
||||
""" Модель видео файлов """
|
||||
|
||||
|
||||
class Videos(TimeStampedModel):
|
||||
file = models.FileField(upload_to='videos/%Y/%m/%d/', verbose_name='Видео',
|
||||
help_text='Загрузите видео', validators=[validate_max_file_size])
|
||||
|
||||
history = HistoricalRecords()
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
self.file_name = f'Video_{self.file_name}' # Префикс "Video_" для видео
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'Видео'
|
||||
verbose_name_plural = 'Видео'
|
||||
ordering = ['-created_at']
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.__class__.__name__}: {self.file_name}'
|
||||
|
||||
|
||||
""" Модель файлов всех типов документов """
|
||||
|
||||
|
||||
class OtherFiles(TimeStampedModel):
|
||||
file = models.FileField(upload_to='documents/%Y/%m/%d/', verbose_name='Документ',
|
||||
help_text='Загрузите документ', validators=[validate_max_file_size])
|
||||
|
||||
history = HistoricalRecords()
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
self.file_name = f'Document_{self.file_name}' # Префикс "Document_" для документов
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
class Meta:
|
||||
verbose_name = 'Документ'
|
||||
verbose_name_plural = 'Документы'
|
||||
ordering = ['-created_at']
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.__class__.__name__}: {self.file_name}'
|
||||
3
system/media/tests.py
Normal file
3
system/media/tests.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
8
system/media/validators.py
Normal file
8
system/media/validators.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
def validate_max_file_size(value):
|
||||
# Максимальный размер файла в байтах (например, 200 МБ = 200 * 1024 * 1024 байт)
|
||||
max_size = 200 * 1024 * 1024
|
||||
if value.size > max_size:
|
||||
raise ValidationError(_('Файл слишком большой. Максимальный размер файла - 200 МБ.'))
|
||||
3
system/media/views.py
Normal file
3
system/media/views.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.shortcuts import render
|
||||
|
||||
# Create your views here.
|
||||
31
tailwind.config.js
Normal file
31
tailwind.config.js
Normal file
@@ -0,0 +1,31 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
darkMode: 'media',
|
||||
content: [
|
||||
'./templates/**/*.html',
|
||||
'./node_modules/flowbite/**/*.js'
|
||||
],
|
||||
theme: {
|
||||
extend: {
|
||||
spacing: {
|
||||
'icon-size': '1.5rem', // размер иконки
|
||||
},
|
||||
colors: {
|
||||
'icon-color': '#333', // цвет иконки
|
||||
},
|
||||
fill: {
|
||||
icon: ['currentColor'], // автоматическое заполнение цветом иконки
|
||||
},
|
||||
fontFamily: {
|
||||
icon: ['Heroicons'], // название шрифта для иконок
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
require('flowbite/plugin'),
|
||||
require('@tailwindcss/forms'),
|
||||
require('@tailwindcss/typography'),
|
||||
require('@tailwindcss/aspect-ratio')
|
||||
]
|
||||
}
|
||||
|
||||
26
templates/components/_base.html
Normal file
26
templates/components/_base.html
Normal file
@@ -0,0 +1,26 @@
|
||||
{% load compress %}
|
||||
{% load static %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
{% include 'components/seo.html' %}
|
||||
<title>{{ title }}</title>
|
||||
<!-- styles -->
|
||||
{% compress css %}
|
||||
<link rel="stylesheet" href="{% static 'src/output.css' %}">
|
||||
{% endcompress %}
|
||||
{% include 'components/css.html' %}
|
||||
<!-- script -->
|
||||
{% include 'components/script.html' %}
|
||||
</head>
|
||||
<body class="antialiased bg-gray-50 dark:bg-gray-900">
|
||||
{% include 'components/navbars/nav.html' %}
|
||||
{% include 'components/navbars/sidebar.html' %}
|
||||
<div class="container mx-auto mt-4">
|
||||
{% block content %}
|
||||
{% endblock content %}
|
||||
</div>
|
||||
<!-- script -->
|
||||
{% include 'components/footer/script.html' %}
|
||||
</body>
|
||||
</html>
|
||||
2
templates/components/css.html
Normal file
2
templates/components/css.html
Normal file
@@ -0,0 +1,2 @@
|
||||
{% load static %}
|
||||
<link rel="icon" type="image/x-icon" href="{% static 'assets/favicon.ico' %}" />
|
||||
44
templates/components/footer/script.html
Normal file
44
templates/components/footer/script.html
Normal file
@@ -0,0 +1,44 @@
|
||||
{% load static %}
|
||||
<!-- Дополнительный скрипт в вашем шаблоне -->
|
||||
<script>
|
||||
var themeToggleDarkIcon = document.getElementById('theme-toggle-dark-icon');
|
||||
var themeToggleLightIcon = document.getElementById('theme-toggle-light-icon');
|
||||
|
||||
// Change the icons inside the button based on previous settings
|
||||
if (localStorage.getItem('color-theme') === 'dark' || (!('color-theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
|
||||
themeToggleLightIcon.classList.remove('hidden');
|
||||
} else {
|
||||
themeToggleDarkIcon.classList.remove('hidden');
|
||||
}
|
||||
|
||||
var themeToggleBtn = document.getElementById('theme-toggle');
|
||||
|
||||
themeToggleBtn.addEventListener('click', function() {
|
||||
|
||||
// toggle icons inside button
|
||||
themeToggleDarkIcon.classList.toggle('hidden');
|
||||
themeToggleLightIcon.classList.toggle('hidden');
|
||||
|
||||
// if set via local storage previously
|
||||
if (localStorage.getItem('color-theme')) {
|
||||
if (localStorage.getItem('color-theme') === 'light') {
|
||||
document.documentElement.classList.add('dark');
|
||||
localStorage.setItem('color-theme', 'dark');
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark');
|
||||
localStorage.setItem('color-theme', 'light');
|
||||
}
|
||||
|
||||
// if NOT set via local storage previously
|
||||
} else {
|
||||
if (document.documentElement.classList.contains('dark')) {
|
||||
document.documentElement.classList.remove('dark');
|
||||
localStorage.setItem('color-theme', 'light');
|
||||
} else {
|
||||
document.documentElement.classList.add('dark');
|
||||
localStorage.setItem('color-theme', 'dark');
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
</script>
|
||||
217
templates/components/navbars/apps.html
Normal file
217
templates/components/navbars/apps.html
Normal file
@@ -0,0 +1,217 @@
|
||||
<button
|
||||
type="button"
|
||||
data-dropdown-toggle="apps-dropdown"
|
||||
class="p-2 text-gray-500 rounded-lg hover:text-gray-900 hover:bg-gray-100 dark:text-gray-400 dark:hover:text-white dark:hover:bg-gray-700 focus:ring-4 focus:ring-gray-300 dark:focus:ring-gray-600"
|
||||
>
|
||||
<span class="sr-only">View notifications</span>
|
||||
<!-- Icon -->
|
||||
<svg
|
||||
class="w-6 h-6"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M5 3a2 2 0 00-2 2v2a2 2 0 002 2h2a2 2 0 002-2V5a2 2 0 00-2-2H5zM5 11a2 2 0 00-2 2v2a2 2 0 002 2h2a2 2 0 002-2v-2a2 2 0 00-2-2H5zM11 5a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V5zM11 13a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z"
|
||||
></path>
|
||||
</svg>
|
||||
</button>
|
||||
<div
|
||||
class="hidden overflow-hidden z-50 my-4 max-w-sm text-base list-none bg-white rounded divide-y divide-gray-100 shadow-lg dark:bg-gray-700 dark:divide-gray-600 rounded-xl"
|
||||
id="apps-dropdown"
|
||||
>
|
||||
<div
|
||||
class="block py-2 px-4 text-base font-medium text-center text-gray-700 bg-gray-50 dark:bg-gray-600 dark:text-gray-300"
|
||||
>
|
||||
Apps
|
||||
</div>
|
||||
<div class="grid grid-cols-3 gap-4 p-4">
|
||||
<a
|
||||
href="#"
|
||||
class="block p-4 text-center rounded-lg hover:bg-gray-100 dark:hover:bg-gray-600 group"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="mx-auto mb-1 w-7 h-7 text-gray-400 group-hover:text-gray-500 dark:text-gray-400 dark:group-hover:text-gray-400"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M10 2a4 4 0 00-4 4v1H5a1 1 0 00-.994.89l-1 9A1 1 0 004 18h12a1 1 0 00.994-1.11l-1-9A1 1 0 0015 7h-1V6a4 4 0 00-4-4zm2 5V6a2 2 0 10-4 0v1h4zm-6 3a1 1 0 112 0 1 1 0 01-2 0zm7-1a1 1 0 100 2 1 1 0 000-2z"
|
||||
clip-rule="evenodd"
|
||||
></path>
|
||||
</svg>
|
||||
<div class="text-sm text-gray-900 dark:text-white">Sales</div>
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
class="block p-4 text-center rounded-lg hover:bg-gray-100 dark:hover:bg-gray-600 group"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="mx-auto mb-1 w-7 h-7 text-gray-400 group-hover:text-gray-500 dark:text-gray-400 dark:group-hover:text-gray-400"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M13 6a3 3 0 11-6 0 3 3 0 016 0zM18 8a2 2 0 11-4 0 2 2 0 014 0zM14 15a4 4 0 00-8 0v3h8v-3zM6 8a2 2 0 11-4 0 2 2 0 014 0zM16 18v-3a5.972 5.972 0 00-.75-2.906A3.005 3.005 0 0119 15v3h-3zM4.75 12.094A5.973 5.973 0 004 15v3H1v-3a3 3 0 013.75-2.906z"
|
||||
></path>
|
||||
</svg>
|
||||
<div class="text-sm text-gray-900 dark:text-white">Users</div>
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
class="block p-4 text-center rounded-lg hover:bg-gray-100 dark:hover:bg-gray-600 group"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="mx-auto mb-1 w-7 h-7 text-gray-400 group-hover:text-gray-500 dark:text-gray-400 dark:group-hover:text-gray-400"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M5 3a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2V5a2 2 0 00-2-2H5zm0 2h10v7h-2l-1 2H8l-1-2H5V5z"
|
||||
clip-rule="evenodd"
|
||||
></path>
|
||||
</svg>
|
||||
<div class="text-sm text-gray-900 dark:text-white">Inbox</div>
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
class="block p-4 text-center rounded-lg hover:bg-gray-100 dark:hover:bg-gray-600 group"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="mx-auto mb-1 w-7 h-7 text-gray-400 group-hover:text-gray-500 dark:text-gray-400 dark:group-hover:text-gray-400"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-6-3a2 2 0 11-4 0 2 2 0 014 0zm-2 4a5 5 0 00-4.546 2.916A5.986 5.986 0 0010 16a5.986 5.986 0 004.546-2.084A5 5 0 0010 11z"
|
||||
clip-rule="evenodd"
|
||||
></path>
|
||||
</svg>
|
||||
<div class="text-sm text-gray-900 dark:text-white">
|
||||
Profile
|
||||
</div>
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
class="block p-4 text-center rounded-lg hover:bg-gray-100 dark:hover:bg-gray-600 group"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="mx-auto mb-1 w-7 h-7 text-gray-400 group-hover:text-gray-500 dark:text-gray-400 dark:group-hover:text-gray-400"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M11.49 3.17c-.38-1.56-2.6-1.56-2.98 0a1.532 1.532 0 01-2.286.948c-1.372-.836-2.942.734-2.106 2.106.54.886.061 2.042-.947 2.287-1.561.379-1.561 2.6 0 2.978a1.532 1.532 0 01.947 2.287c-.836 1.372.734 2.942 2.106 2.106a1.532 1.532 0 012.287.947c.379 1.561 2.6 1.561 2.978 0a1.533 1.533 0 012.287-.947c1.372.836 2.942-.734 2.106-2.106a1.533 1.533 0 01.947-2.287c1.561-.379 1.561-2.6 0-2.978a1.532 1.532 0 01-.947-2.287c.836-1.372-.734-2.942-2.106-2.106a1.532 1.532 0 01-2.287-.947zM10 13a3 3 0 100-6 3 3 0 000 6z"
|
||||
clip-rule="evenodd"
|
||||
></path>
|
||||
</svg>
|
||||
<div class="text-sm text-gray-900 dark:text-white">
|
||||
Settings
|
||||
</div>
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
class="block p-4 text-center rounded-lg hover:bg-gray-100 dark:hover:bg-gray-600 group"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="mx-auto mb-1 w-7 h-7 text-gray-400 group-hover:text-gray-500 dark:text-gray-400 dark:group-hover:text-gray-400"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path d="M4 3a2 2 0 100 4h12a2 2 0 100-4H4z"></path>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M3 8h14v7a2 2 0 01-2 2H5a2 2 0 01-2-2V8zm5 3a1 1 0 011-1h2a1 1 0 110 2H9a1 1 0 01-1-1z"
|
||||
clip-rule="evenodd"
|
||||
></path>
|
||||
</svg>
|
||||
<div class="text-sm text-gray-900 dark:text-white">
|
||||
Products
|
||||
</div>
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
class="block p-4 text-center rounded-lg hover:bg-gray-100 dark:hover:bg-gray-600 group"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="mx-auto mb-1 w-7 h-7 text-gray-400 group-hover:text-gray-500 dark:text-gray-400 dark:group-hover:text-gray-400"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M8.433 7.418c.155-.103.346-.196.567-.267v1.698a2.305 2.305 0 01-.567-.267C8.07 8.34 8 8.114 8 8c0-.114.07-.34.433-.582zM11 12.849v-1.698c.22.071.412.164.567.267.364.243.433.468.433.582 0 .114-.07.34-.433.582a2.305 2.305 0 01-.567.267z"
|
||||
></path>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M10 18a8 8 0 100-16 8 8 0 000 16zm1-13a1 1 0 10-2 0v.092a4.535 4.535 0 00-1.676.662C6.602 6.234 6 7.009 6 8c0 .99.602 1.765 1.324 2.246.48.32 1.054.545 1.676.662v1.941c-.391-.127-.68-.317-.843-.504a1 1 0 10-1.51 1.31c.562.649 1.413 1.076 2.353 1.253V15a1 1 0 102 0v-.092a4.535 4.535 0 001.676-.662C13.398 13.766 14 12.991 14 12c0-.99-.602-1.765-1.324-2.246A4.535 4.535 0 0011 9.092V7.151c.391.127.68.317.843.504a1 1 0 101.511-1.31c-.563-.649-1.413-1.076-2.354-1.253V5z"
|
||||
clip-rule="evenodd"
|
||||
></path>
|
||||
</svg>
|
||||
<div class="text-sm text-gray-900 dark:text-white">
|
||||
Pricing
|
||||
</div>
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
class="block p-4 text-center rounded-lg hover:bg-gray-100 dark:hover:bg-gray-600 group"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="mx-auto mb-1 w-7 h-7 text-gray-400 group-hover:text-gray-500 dark:text-gray-400 dark:group-hover:text-gray-400"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M5 2a2 2 0 00-2 2v14l3.5-2 3.5 2 3.5-2 3.5 2V4a2 2 0 00-2-2H5zm2.5 3a1.5 1.5 0 100 3 1.5 1.5 0 000-3zm6.207.293a1 1 0 00-1.414 0l-6 6a1 1 0 101.414 1.414l6-6a1 1 0 000-1.414zM12.5 10a1.5 1.5 0 100 3 1.5 1.5 0 000-3z"
|
||||
clip-rule="evenodd"
|
||||
></path>
|
||||
</svg>
|
||||
<div class="text-sm text-gray-900 dark:text-white">
|
||||
Billing
|
||||
</div>
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
class="block p-4 text-center rounded-lg hover:bg-gray-100 dark:hover:bg-gray-600 group"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="mx-auto mb-1 w-7 h-7 text-gray-400 group-hover:text-gray-500 dark:text-gray-400 dark:group-hover:text-gray-400"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1"
|
||||
></path>
|
||||
</svg>
|
||||
<div class="text-sm text-gray-900 dark:text-white">
|
||||
Logout
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
5
templates/components/navbars/burger.html
Normal file
5
templates/components/navbars/burger.html
Normal file
@@ -0,0 +1,5 @@
|
||||
|
||||
<button data-drawer-target="drawer-navigation" data-drawer-toggle="drawer-navigation" aria-controls="drawer-navigation" class="p-2 mr-2 text-gray-600 rounded-lg cursor-pointer md:hidden hover:text-gray-900 hover:bg-gray-100 focus:bg-gray-100 dark:focus:bg-gray-700 focus:ring-2 focus:ring-gray-100 dark:focus:ring-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white">
|
||||
{% include 'icons/burger.html' %}
|
||||
<span class="sr-only">Toggle sidebar</span>
|
||||
</button>
|
||||
10
templates/components/navbars/dark_mode.html
Normal file
10
templates/components/navbars/dark_mode.html
Normal file
@@ -0,0 +1,10 @@
|
||||
{% load static %}
|
||||
<!-- Кнопка переключения темы -->
|
||||
<button id="theme-toggle" type="button" class="text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none focus:ring-4 focus:ring-gray-200 dark:focus:ring-gray-700 rounded-lg text-sm p-2.5">
|
||||
<svg id="theme-toggle-dark-icon" class="hidden w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z"></path>
|
||||
</svg>
|
||||
<svg id="theme-toggle-light-icon" class="hidden w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z" fill-rule="evenodd" clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
</button>
|
||||
4
templates/components/navbars/logo.html
Normal file
4
templates/components/navbars/logo.html
Normal file
@@ -0,0 +1,4 @@
|
||||
{% load static %}
|
||||
<a href="{% url 'main' %}" class="flex items-center justify-between mr-4">
|
||||
<img src="{% static 'img/logo.png' %}" class="mr-3 h-8" alt="VikiLeo.shop Logo" />
|
||||
</a>
|
||||
22
templates/components/navbars/nav.html
Normal file
22
templates/components/navbars/nav.html
Normal file
@@ -0,0 +1,22 @@
|
||||
{% load static %}
|
||||
<nav class="bg-white border-b border-gray-200 px-4 py-2.5 dark:bg-gray-800 dark:border-gray-700 fixed left-0 right-0 top-0 z-50">
|
||||
<div class="flex flex-wrap justify-between items-center">
|
||||
<div class="flex justify-start items-center">
|
||||
{% include 'components/navbars/burger.html' %}
|
||||
{% include 'components/navbars/logo.html' %}
|
||||
{% include 'components/navbars/search.html' %}
|
||||
</div>
|
||||
<div class="flex items-center lg:order-2">
|
||||
<!-- Search -->
|
||||
{% include 'components/navbars/search_mini.html' %}
|
||||
<!-- Dark mode -->
|
||||
{% include 'components/navbars/dark_mode.html' %}
|
||||
<!-- Notifications -->
|
||||
{% include 'components/navbars/notifications.html' %}
|
||||
<!-- Apps -->
|
||||
{% include 'components/navbars/apps.html' %}
|
||||
<!-- Profiles -->
|
||||
{% include 'components/navbars/profiles.html' %}
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
261
templates/components/navbars/notifications.html
Normal file
261
templates/components/navbars/notifications.html
Normal file
@@ -0,0 +1,261 @@
|
||||
<button type="button" data-dropdown-toggle="notification-dropdown" class="p-2 mr-1 text-gray-500 rounded-lg hover:text-gray-900 hover:bg-gray-100 dark:text-gray-400 dark:hover:text-white dark:hover:bg-gray-700 focus:ring-4 focus:ring-gray-300 dark:focus:ring-gray-600">
|
||||
<span class="sr-only">View notifications</span>
|
||||
{% include 'icons/notifications.html' %}
|
||||
</button>
|
||||
<div class="hidden overflow-hidden z-50 my-4 max-w-sm text-base list-none bg-white rounded divide-y divide-gray-100 shadow-lg dark:divide-gray-600 dark:bg-gray-700 rounded-xl" id="notification-dropdown">
|
||||
<div class="block py-2 px-4 text-base font-medium text-center text-gray-700 bg-gray-50 dark:bg-gray-600 dark:text-gray-300">
|
||||
Notifications
|
||||
</div>
|
||||
<div>
|
||||
<a href="#" class="flex py-3 px-4 border-b hover:bg-gray-100 dark:hover:bg-gray-600 dark:border-gray-600">
|
||||
<div class="flex-shrink-0">
|
||||
<img
|
||||
class="w-11 h-11 rounded-full"
|
||||
src="https://flowbite.s3.amazonaws.com/blocks/marketing-ui/avatars/bonnie-green.png"
|
||||
alt="Bonnie Green avatar"
|
||||
/>
|
||||
<div
|
||||
class="flex absolute justify-center items-center ml-6 -mt-5 w-5 h-5 rounded-full border border-white bg-primary-700 dark:border-gray-700"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="w-3 h-3 text-white"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M8.707 7.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l2-2a1 1 0 00-1.414-1.414L11 7.586V3a1 1 0 10-2 0v4.586l-.293-.293z"
|
||||
></path>
|
||||
<path
|
||||
d="M3 5a2 2 0 012-2h1a1 1 0 010 2H5v7h2l1 2h4l1-2h2V5h-1a1 1 0 110-2h1a2 2 0 012 2v10a2 2 0 01-2 2H5a2 2 0 01-2-2V5z"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pl-3 w-full">
|
||||
<div
|
||||
class="text-gray-500 font-normal text-sm mb-1.5 dark:text-gray-400"
|
||||
>
|
||||
New message from
|
||||
<span class="font-semibold text-gray-900 dark:text-white"
|
||||
>Bonnie Green</span
|
||||
>: "Hey, what's up? All set for the presentation?"
|
||||
</div>
|
||||
<div
|
||||
class="text-xs font-medium text-primary-600 dark:text-primary-500"
|
||||
>
|
||||
a few moments ago
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
class="flex py-3 px-4 border-b hover:bg-gray-100 dark:hover:bg-gray-600 dark:border-gray-600"
|
||||
>
|
||||
<div class="flex-shrink-0">
|
||||
<img
|
||||
class="w-11 h-11 rounded-full"
|
||||
src="https://flowbite.s3.amazonaws.com/blocks/marketing-ui/avatars/jese-leos.png"
|
||||
alt="Jese Leos avatar"
|
||||
/>
|
||||
<div
|
||||
class="flex absolute justify-center items-center ml-6 -mt-5 w-5 h-5 bg-gray-900 rounded-full border border-white dark:border-gray-700"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="w-3 h-3 text-white"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M8 9a3 3 0 100-6 3 3 0 000 6zM8 11a6 6 0 016 6H2a6 6 0 016-6zM16 7a1 1 0 10-2 0v1h-1a1 1 0 100 2h1v1a1 1 0 102 0v-1h1a1 1 0 100-2h-1V7z"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pl-3 w-full">
|
||||
<div
|
||||
class="text-gray-500 font-normal text-sm mb-1.5 dark:text-gray-400"
|
||||
>
|
||||
<span class="font-semibold text-gray-900 dark:text-white"
|
||||
>Jese leos</span
|
||||
>
|
||||
and
|
||||
<span class="font-medium text-gray-900 dark:text-white"
|
||||
>5 others</span
|
||||
>
|
||||
started following you.
|
||||
</div>
|
||||
<div
|
||||
class="text-xs font-medium text-primary-600 dark:text-primary-500"
|
||||
>
|
||||
10 minutes ago
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
class="flex py-3 px-4 border-b hover:bg-gray-100 dark:hover:bg-gray-600 dark:border-gray-600"
|
||||
>
|
||||
<div class="flex-shrink-0">
|
||||
<img
|
||||
class="w-11 h-11 rounded-full"
|
||||
src="https://flowbite.s3.amazonaws.com/blocks/marketing-ui/avatars/joseph-mcfall.png"
|
||||
alt="Joseph McFall avatar"
|
||||
/>
|
||||
<div
|
||||
class="flex absolute justify-center items-center ml-6 -mt-5 w-5 h-5 bg-red-600 rounded-full border border-white dark:border-gray-700"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="w-3 h-3 text-white"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M3.172 5.172a4 4 0 015.656 0L10 6.343l1.172-1.171a4 4 0 115.656 5.656L10 17.657l-6.828-6.829a4 4 0 010-5.656z"
|
||||
clip-rule="evenodd"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pl-3 w-full">
|
||||
<div
|
||||
class="text-gray-500 font-normal text-sm mb-1.5 dark:text-gray-400"
|
||||
>
|
||||
<span class="font-semibold text-gray-900 dark:text-white"
|
||||
>Joseph Mcfall</span
|
||||
>
|
||||
and
|
||||
<span class="font-medium text-gray-900 dark:text-white"
|
||||
>141 others</span
|
||||
>
|
||||
love your story. See it and view more stories.
|
||||
</div>
|
||||
<div
|
||||
class="text-xs font-medium text-primary-600 dark:text-primary-500"
|
||||
>
|
||||
44 minutes ago
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
class="flex py-3 px-4 border-b hover:bg-gray-100 dark:hover:bg-gray-600 dark:border-gray-600"
|
||||
>
|
||||
<div class="flex-shrink-0">
|
||||
<img
|
||||
class="w-11 h-11 rounded-full"
|
||||
src="https://flowbite.s3.amazonaws.com/blocks/marketing-ui/avatars/roberta-casas.png"
|
||||
alt="Roberta Casas image"
|
||||
/>
|
||||
<div
|
||||
class="flex absolute justify-center items-center ml-6 -mt-5 w-5 h-5 bg-green-400 rounded-full border border-white dark:border-gray-700"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="w-3 h-3 text-white"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M18 13V5a2 2 0 00-2-2H4a2 2 0 00-2 2v8a2 2 0 002 2h3l3 3 3-3h3a2 2 0 002-2zM5 7a1 1 0 011-1h8a1 1 0 110 2H6a1 1 0 01-1-1zm1 3a1 1 0 100 2h3a1 1 0 100-2H6z"
|
||||
clip-rule="evenodd"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pl-3 w-full">
|
||||
<div
|
||||
class="text-gray-500 font-normal text-sm mb-1.5 dark:text-gray-400"
|
||||
>
|
||||
<span class="font-semibold text-gray-900 dark:text-white"
|
||||
>Leslie Livingston</span
|
||||
>
|
||||
mentioned you in a comment:
|
||||
<span
|
||||
class="font-medium text-primary-600 dark:text-primary-500"
|
||||
>@bonnie.green</span
|
||||
>
|
||||
what do you say?
|
||||
</div>
|
||||
<div
|
||||
class="text-xs font-medium text-primary-600 dark:text-primary-500"
|
||||
>
|
||||
1 hour ago
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
class="flex py-3 px-4 hover:bg-gray-100 dark:hover:bg-gray-600"
|
||||
>
|
||||
<div class="flex-shrink-0">
|
||||
<img
|
||||
class="w-11 h-11 rounded-full"
|
||||
src="https://flowbite.s3.amazonaws.com/blocks/marketing-ui/avatars/robert-brown.png"
|
||||
alt="Robert image"
|
||||
/>
|
||||
<div
|
||||
class="flex absolute justify-center items-center ml-6 -mt-5 w-5 h-5 bg-purple-500 rounded-full border border-white dark:border-gray-700"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="w-3 h-3 text-white"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M2 6a2 2 0 012-2h6a2 2 0 012 2v8a2 2 0 01-2 2H4a2 2 0 01-2-2V6zM14.553 7.106A1 1 0 0014 8v4a1 1 0 00.553.894l2 1A1 1 0 0018 13V7a1 1 0 00-1.447-.894l-2 1z"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pl-3 w-full">
|
||||
<div
|
||||
class="text-gray-500 font-normal text-sm mb-1.5 dark:text-gray-400"
|
||||
>
|
||||
<span class="font-semibold text-gray-900 dark:text-white"
|
||||
>Robert Brown</span
|
||||
>
|
||||
posted a new video: Glassmorphism - learn how to implement
|
||||
the new design trend.
|
||||
</div>
|
||||
<div
|
||||
class="text-xs font-medium text-primary-600 dark:text-primary-500"
|
||||
>
|
||||
3 hours ago
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<a
|
||||
href="#"
|
||||
class="block py-2 text-md font-medium text-center text-gray-900 bg-gray-50 hover:bg-gray-100 dark:bg-gray-600 dark:text-white dark:hover:underline"
|
||||
>
|
||||
<div class="inline-flex items-center">
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="mr-2 w-4 h-4 text-gray-500 dark:text-gray-400"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path d="M10 12a2 2 0 100-4 2 2 0 000 4z"></path>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M.458 10C1.732 5.943 5.522 3 10 3s8.268 2.943 9.542 7c-1.274 4.057-5.064 7-9.542 7S1.732 14.057.458 10zM14 10a4 4 0 11-8 0 4 4 0 018 0z"
|
||||
clip-rule="evenodd"
|
||||
></path>
|
||||
</svg>
|
||||
View all
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
152
templates/components/navbars/profiles.html
Normal file
152
templates/components/navbars/profiles.html
Normal file
@@ -0,0 +1,152 @@
|
||||
<div class="text-end">
|
||||
{% if not request.user.is_authenticated %}
|
||||
<a class="btn btn-outline-light me-2" href="{% url 'account-login' %}">Авторизация</a>
|
||||
<a class="btn btn-outline-warning" href="{% url 'account-registration' %}">Регистрация</a>
|
||||
{% else %}
|
||||
<span class="navbar-text text-white">Войти в профиль: {% if request.user.is_authenticated %}
|
||||
<a href="#" class="btn btn-white">
|
||||
{{ request.accounts.username }}
|
||||
</a>
|
||||
{% else %} гоcть!{% endif %}
|
||||
<a href="{% url 'logout' %}" class="btn btn-outline-light me-2">Выйти</a>
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="flex mx-3 text-sm bg-gray-800 rounded-full md:mr-0 focus:ring-4 focus:ring-gray-300 dark:focus:ring-gray-600"
|
||||
id="user-menu-button"
|
||||
aria-expanded="false"
|
||||
data-dropdown-toggle="dropdown"
|
||||
>
|
||||
<span class="sr-only">Open user menu</span>
|
||||
<img
|
||||
class="w-8 h-8 rounded-full"
|
||||
src="https://flowbite.s3.amazonaws.com/blocks/marketing-ui/avatars/michael-gough.png"
|
||||
alt="user photo"
|
||||
/>
|
||||
</button>
|
||||
<!-- Dropdown menu -->
|
||||
<div
|
||||
class="hidden z-50 my-4 w-56 text-base list-none bg-white rounded divide-y divide-gray-100 shadow dark:bg-gray-700 dark:divide-gray-600 rounded-xl"
|
||||
id="dropdown"
|
||||
>
|
||||
<div class="py-3 px-4">
|
||||
<span
|
||||
class="block text-sm font-semibold text-gray-900 dark:text-white"
|
||||
>Neil Sims</span
|
||||
>
|
||||
<span
|
||||
class="block text-sm text-gray-900 truncate dark:text-white"
|
||||
>name@flowbite.com</span
|
||||
>
|
||||
</div>
|
||||
<ul
|
||||
class="py-1 text-gray-700 dark:text-gray-300"
|
||||
aria-labelledby="dropdown"
|
||||
>
|
||||
<li>
|
||||
<a
|
||||
href="#"
|
||||
class="block py-2 px-4 text-sm hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-400 dark:hover:text-white"
|
||||
>My profile</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#"
|
||||
class="block py-2 px-4 text-sm hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-400 dark:hover:text-white"
|
||||
>Account settings</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
<ul
|
||||
class="py-1 text-gray-700 dark:text-gray-300"
|
||||
aria-labelledby="dropdown"
|
||||
>
|
||||
<li>
|
||||
<a
|
||||
href="#"
|
||||
class="flex items-center py-2 px-4 text-sm hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white"
|
||||
><svg
|
||||
class="mr-2 w-5 h-5 text-gray-400"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M3.172 5.172a4 4 0 015.656 0L10 6.343l1.172-1.171a4 4 0 115.656 5.656L10 17.657l-6.828-6.829a4 4 0 010-5.656z"
|
||||
clip-rule="evenodd"
|
||||
></path>
|
||||
</svg>
|
||||
My likes</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#"
|
||||
class="flex items-center py-2 px-4 text-sm hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white"
|
||||
><svg
|
||||
class="mr-2 w-5 h-5 text-gray-400"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M7 3a1 1 0 000 2h6a1 1 0 100-2H7zM4 7a1 1 0 011-1h10a1 1 0 110 2H5a1 1 0 01-1-1zM2 11a2 2 0 012-2h12a2 2 0 012 2v4a2 2 0 01-2 2H4a2 2 0 01-2-2v-4z"
|
||||
></path>
|
||||
</svg>
|
||||
Collections</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#"
|
||||
class="flex justify-between items-center py-2 px-4 text-sm hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white"
|
||||
>
|
||||
<span class="flex items-center">
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="mr-2 w-5 h-5 text-primary-600 dark:text-primary-500"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M12.395 2.553a1 1 0 00-1.45-.385c-.345.23-.614.558-.822.88-.214.33-.403.713-.57 1.116-.334.804-.614 1.768-.84 2.734a31.365 31.365 0 00-.613 3.58 2.64 2.64 0 01-.945-1.067c-.328-.68-.398-1.534-.398-2.654A1 1 0 005.05 6.05 6.981 6.981 0 003 11a7 7 0 1011.95-4.95c-.592-.591-.98-.985-1.348-1.467-.363-.476-.724-1.063-1.207-2.03zM12.12 15.12A3 3 0 017 13s.879.5 2.5.5c0-1 .5-4 1.25-4.5.5 1 .786 1.293 1.371 1.879A2.99 2.99 0 0113 13a2.99 2.99 0 01-.879 2.121z"
|
||||
clip-rule="evenodd"
|
||||
></path>
|
||||
</svg>
|
||||
Pro version
|
||||
</span>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="w-5 h-5 text-gray-400"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
|
||||
clip-rule="evenodd"
|
||||
></path>
|
||||
</svg>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul
|
||||
class="py-1 text-gray-700 dark:text-gray-300"
|
||||
aria-labelledby="dropdown"
|
||||
>
|
||||
<li>
|
||||
<a
|
||||
href="#"
|
||||
class="block py-2 px-4 text-sm hover:bg-gray-100 dark:hover:bg-gray-600 dark:hover:text-white"
|
||||
>Sign out</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
18
templates/components/navbars/search.html
Normal file
18
templates/components/navbars/search.html
Normal file
@@ -0,0 +1,18 @@
|
||||
|
||||
<form action="#" method="GET" class="hidden md:block md:pl-2">
|
||||
<label for="topbar-search" class="sr-only">Search</label>
|
||||
<div class="relative md:w-64 md:w-96">
|
||||
<div
|
||||
class="flex absolute inset-y-0 left-0 items-center pl-3 pointer-events-none"
|
||||
>
|
||||
{% include 'icons/search.html' %}
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
name="email"
|
||||
id="topbar-search"
|
||||
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 block w-full pl-10 p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500"
|
||||
placeholder="Search"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
6
templates/components/navbars/search_mini.html
Normal file
6
templates/components/navbars/search_mini.html
Normal file
@@ -0,0 +1,6 @@
|
||||
<button type="button" data-drawer-toggle="drawer-navigation" aria-controls="drawer-navigation" class="p-2 mr-1 text-gray-500 rounded-lg md:hidden hover:text-gray-900 hover:bg-gray-100 dark:text-gray-400 dark:hover:text-white dark:hover:bg-gray-700 focus:ring-4 focus:ring-gray-300 dark:focus:ring-gray-600">
|
||||
<span class="sr-only">Toggle search</span>
|
||||
<svg aria-hidden="true" class="w-6 h-6" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
||||
<path clip-rule="evenodd" fill-rule="evenodd" d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z"></path>
|
||||
</svg>
|
||||
</button>
|
||||
578
templates/components/navbars/sidebar.html
Normal file
578
templates/components/navbars/sidebar.html
Normal file
@@ -0,0 +1,578 @@
|
||||
<aside
|
||||
class="fixed top-0 left-0 z-40 w-64 h-screen pt-14 transition-transform -translate-x-full bg-white border-r border-gray-200 md:translate-x-0 dark:bg-gray-800 dark:border-gray-700"
|
||||
aria-label="Sidenav"
|
||||
id="drawer-navigation"
|
||||
>
|
||||
<div class="overflow-y-auto py-5 px-3 h-full bg-white dark:bg-gray-800">
|
||||
<form action="#" method="GET" class="md:hidden mb-2">
|
||||
<label for="sidebar-search" class="sr-only">Search</label>
|
||||
<div class="relative">
|
||||
<div
|
||||
class="flex absolute inset-y-0 left-0 items-center pl-3 pointer-events-none"
|
||||
>
|
||||
<svg
|
||||
class="w-5 h-5 text-gray-500 dark:text-gray-400"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
name="search"
|
||||
id="sidebar-search"
|
||||
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 block w-full pl-10 p-2 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500"
|
||||
placeholder="Search"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
<ul class="space-y-2">
|
||||
<li>
|
||||
<a
|
||||
href="#"
|
||||
class="flex items-center p-2 text-base font-medium text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="w-6 h-6 text-gray-500 transition duration-75 dark:text-gray-400 group-hover:text-gray-900 dark:group-hover:text-white"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path d="M2 10a8 8 0 018-8v8h8a8 8 0 11-16 0z"></path>
|
||||
<path d="M12 2.252A8.014 8.014 0 0117.748 8H12V2.252z"></path>
|
||||
</svg>
|
||||
<span class="ml-3">Overview</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<button
|
||||
type="button"
|
||||
class="flex items-center p-2 w-full text-base font-medium text-gray-900 rounded-lg transition duration-75 group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700"
|
||||
aria-controls="dropdown-pages"
|
||||
data-collapse-toggle="dropdown-pages"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="flex-shrink-0 w-6 h-6 text-gray-500 transition duration-75 group-hover:text-gray-900 dark:text-gray-400 dark:group-hover:text-white"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M4 4a2 2 0 012-2h4.586A2 2 0 0112 2.586L15.414 6A2 2 0 0116 7.414V16a2 2 0 01-2 2H6a2 2 0 01-2-2V4zm2 6a1 1 0 011-1h6a1 1 0 110 2H7a1 1 0 01-1-1zm1 3a1 1 0 100 2h6a1 1 0 100-2H7z"
|
||||
clip-rule="evenodd"
|
||||
></path>
|
||||
</svg>
|
||||
<span class="flex-1 ml-3 text-left whitespace-nowrap"
|
||||
>Pages</span
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="w-6 h-6"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
||||
clip-rule="evenodd"
|
||||
></path>
|
||||
</svg>
|
||||
</button>
|
||||
<ul id="dropdown-pages" class="hidden py-2 space-y-2">
|
||||
<li>
|
||||
<a
|
||||
href="#"
|
||||
class="flex items-center p-2 pl-11 w-full text-base font-medium text-gray-900 rounded-lg transition duration-75 group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700"
|
||||
>Settings</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#"
|
||||
class="flex items-center p-2 pl-11 w-full text-base font-medium text-gray-900 rounded-lg transition duration-75 group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700"
|
||||
>Kanban</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#"
|
||||
class="flex items-center p-2 pl-11 w-full text-base font-medium text-gray-900 rounded-lg transition duration-75 group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700"
|
||||
>Calendar</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<button
|
||||
type="button"
|
||||
class="flex items-center p-2 w-full text-base font-medium text-gray-900 rounded-lg transition duration-75 group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700"
|
||||
aria-controls="dropdown-sales"
|
||||
data-collapse-toggle="dropdown-sales"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="flex-shrink-0 w-6 h-6 text-gray-500 transition duration-75 group-hover:text-gray-900 dark:text-gray-400 dark:group-hover:text-white"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M10 2a4 4 0 00-4 4v1H5a1 1 0 00-.994.89l-1 9A1 1 0 004 18h12a1 1 0 00.994-1.11l-1-9A1 1 0 0015 7h-1V6a4 4 0 00-4-4zm2 5V6a2 2 0 10-4 0v1h4zm-6 3a1 1 0 112 0 1 1 0 01-2 0zm7-1a1 1 0 100 2 1 1 0 000-2z"
|
||||
clip-rule="evenodd"
|
||||
></path>
|
||||
</svg>
|
||||
<span class="flex-1 ml-3 text-left whitespace-nowrap"
|
||||
>Sales</span
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="w-6 h-6"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
||||
clip-rule="evenodd"
|
||||
></path>
|
||||
</svg>
|
||||
</button>
|
||||
<ul id="dropdown-sales" class="hidden py-2 space-y-2">
|
||||
<li>
|
||||
<a
|
||||
href="#"
|
||||
class="flex items-center p-2 pl-11 w-full text-base font-medium text-gray-900 rounded-lg transition duration-75 group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700"
|
||||
>Products</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#"
|
||||
class="flex items-center p-2 pl-11 w-full text-base font-medium text-gray-900 rounded-lg transition duration-75 group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700"
|
||||
>Billing</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#"
|
||||
class="flex items-center p-2 pl-11 w-full text-base font-medium text-gray-900 rounded-lg transition duration-75 group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700"
|
||||
>Invoice</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#"
|
||||
class="flex items-center p-2 text-base font-medium text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="flex-shrink-0 w-6 h-6 text-gray-500 transition duration-75 dark:text-gray-400 group-hover:text-gray-900 dark:group-hover:text-white"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M8.707 7.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l2-2a1 1 0 00-1.414-1.414L11 7.586V3a1 1 0 10-2 0v4.586l-.293-.293z"
|
||||
></path>
|
||||
<path
|
||||
d="M3 5a2 2 0 012-2h1a1 1 0 010 2H5v7h2l1 2h4l1-2h2V5h-1a1 1 0 110-2h1a2 2 0 012 2v10a2 2 0 01-2 2H5a2 2 0 01-2-2V5z"
|
||||
></path>
|
||||
</svg>
|
||||
<span class="flex-1 ml-3 whitespace-nowrap">Messages</span>
|
||||
<span
|
||||
class="inline-flex justify-center items-center w-5 h-5 text-xs font-semibold rounded-full text-primary-800 bg-primary-100 dark:bg-primary-200 dark:text-primary-800"
|
||||
>
|
||||
4
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<button
|
||||
type="button"
|
||||
class="flex items-center p-2 w-full text-base font-medium text-gray-900 rounded-lg transition duration-75 group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700"
|
||||
aria-controls="dropdown-authentication"
|
||||
data-collapse-toggle="dropdown-authentication"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="flex-shrink-0 w-6 h-6 text-gray-500 transition duration-75 group-hover:text-gray-900 dark:text-gray-400 dark:group-hover:text-white"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z"
|
||||
clip-rule="evenodd"
|
||||
></path>
|
||||
</svg>
|
||||
<span class="flex-1 ml-3 text-left whitespace-nowrap"
|
||||
>Authentication</span
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="w-6 h-6"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
||||
clip-rule="evenodd"
|
||||
></path>
|
||||
</svg>
|
||||
</button>
|
||||
<ul id="dropdown-authentication" class="hidden py-2 space-y-2">
|
||||
<li>
|
||||
<a
|
||||
href="#"
|
||||
class="flex items-center p-2 pl-11 w-full text-base font-medium text-gray-900 rounded-lg transition duration-75 group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700"
|
||||
>Sign In</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#"
|
||||
class="flex items-center p-2 pl-11 w-full text-base font-medium text-gray-900 rounded-lg transition duration-75 group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700"
|
||||
>Sign Up</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#"
|
||||
class="flex items-center p-2 pl-11 w-full text-base font-medium text-gray-900 rounded-lg transition duration-75 group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700"
|
||||
>Forgot Password</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<ul
|
||||
class="pt-5 mt-5 space-y-2 border-t border-gray-200 dark:border-gray-700"
|
||||
>
|
||||
<li>
|
||||
<a
|
||||
href="#"
|
||||
class="flex items-center p-2 text-base font-medium text-gray-900 rounded-lg transition duration-75 hover:bg-gray-100 dark:hover:bg-gray-700 dark:text-white group"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="flex-shrink-0 w-6 h-6 text-gray-500 transition duration-75 dark:text-gray-400 group-hover:text-gray-900 dark:group-hover:text-white"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path d="M9 2a1 1 0 000 2h2a1 1 0 100-2H9z"></path>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M4 5a2 2 0 012-2 3 3 0 003 3h2a3 3 0 003-3 2 2 0 012 2v11a2 2 0 01-2 2H6a2 2 0 01-2-2V5zm3 4a1 1 0 000 2h.01a1 1 0 100-2H7zm3 0a1 1 0 000 2h3a1 1 0 100-2h-3zm-3 4a1 1 0 100 2h.01a1 1 0 100-2H7zm3 0a1 1 0 100 2h3a1 1 0 100-2h-3z"
|
||||
clip-rule="evenodd"
|
||||
></path>
|
||||
</svg>
|
||||
<span class="ml-3">Docs</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#"
|
||||
class="flex items-center p-2 text-base font-medium text-gray-900 rounded-lg transition duration-75 hover:bg-gray-100 dark:hover:bg-gray-700 dark:text-white group"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="flex-shrink-0 w-6 h-6 text-gray-500 transition duration-75 dark:text-gray-400 group-hover:text-gray-900 dark:group-hover:text-white"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M7 3a1 1 0 000 2h6a1 1 0 100-2H7zM4 7a1 1 0 011-1h10a1 1 0 110 2H5a1 1 0 01-1-1zM2 11a2 2 0 012-2h12a2 2 0 012 2v4a2 2 0 01-2 2H4a2 2 0 01-2-2v-4z"
|
||||
></path>
|
||||
</svg>
|
||||
<span class="ml-3">Components</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#"
|
||||
class="flex items-center p-2 text-base font-medium text-gray-900 rounded-lg transition duration-75 hover:bg-gray-100 dark:hover:bg-gray-700 dark:text-white group"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="flex-shrink-0 w-6 h-6 text-gray-500 transition duration-75 dark:text-gray-400 group-hover:text-gray-900 dark:group-hover:text-white"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-2 0c0 .993-.241 1.929-.668 2.754l-1.524-1.525a3.997 3.997 0 00.078-2.183l1.562-1.562C15.802 8.249 16 9.1 16 10zm-5.165 3.913l1.58 1.58A5.98 5.98 0 0110 16a5.976 5.976 0 01-2.516-.552l1.562-1.562a4.006 4.006 0 001.789.027zm-4.677-2.796a4.002 4.002 0 01-.041-2.08l-.08.08-1.53-1.533A5.98 5.98 0 004 10c0 .954.223 1.856.619 2.657l1.54-1.54zm1.088-6.45A5.974 5.974 0 0110 4c.954 0 1.856.223 2.657.619l-1.54 1.54a4.002 4.002 0 00-2.346.033L7.246 4.668zM12 10a2 2 0 11-4 0 2 2 0 014 0z"
|
||||
clip-rule="evenodd"
|
||||
></path>
|
||||
</svg>
|
||||
<span class="ml-3">Help</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div
|
||||
class="hidden absolute bottom-0 left-0 justify-center p-4 space-x-4 w-full lg:flex bg-white dark:bg-gray-800 z-20"
|
||||
>
|
||||
<a
|
||||
href="#"
|
||||
class="inline-flex justify-center p-2 text-gray-500 rounded cursor-pointer dark:text-gray-400 hover:text-gray-900 dark:hover:text-white hover:bg-gray-100 dark:hover:bg-gray-600"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="w-6 h-6"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M5 4a1 1 0 00-2 0v7.268a2 2 0 000 3.464V16a1 1 0 102 0v-1.268a2 2 0 000-3.464V4zM11 4a1 1 0 10-2 0v1.268a2 2 0 000 3.464V16a1 1 0 102 0V8.732a2 2 0 000-3.464V4zM16 3a1 1 0 011 1v7.268a2 2 0 010 3.464V16a1 1 0 11-2 0v-1.268a2 2 0 010-3.464V4a1 1 0 011-1z"
|
||||
></path>
|
||||
</svg>
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
data-tooltip-target="tooltip-settings"
|
||||
class="inline-flex justify-center p-2 text-gray-500 rounded cursor-pointer dark:text-gray-400 dark:hover:text-white hover:text-gray-900 hover:bg-gray-100 dark:hover:bg-gray-600"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="w-6 h-6"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M11.49 3.17c-.38-1.56-2.6-1.56-2.98 0a1.532 1.532 0 01-2.286.948c-1.372-.836-2.942.734-2.106 2.106.54.886.061 2.042-.947 2.287-1.561.379-1.561 2.6 0 2.978a1.532 1.532 0 01.947 2.287c-.836 1.372.734 2.942 2.106 2.106a1.532 1.532 0 012.287.947c.379 1.561 2.6 1.561 2.978 0a1.533 1.533 0 012.287-.947c1.372.836 2.942-.734 2.106-2.106a1.533 1.533 0 01.947-2.287c1.561-.379 1.561-2.6 0-2.978a1.532 1.532 0 01-.947-2.287c.836-1.372-.734-2.942-2.106-2.106a1.532 1.532 0 01-2.287-.947zM10 13a3 3 0 100-6 3 3 0 000 6z"
|
||||
clip-rule="evenodd"
|
||||
></path>
|
||||
</svg>
|
||||
</a>
|
||||
<div
|
||||
id="tooltip-settings"
|
||||
role="tooltip"
|
||||
class="inline-block absolute invisible z-10 py-2 px-3 text-sm font-medium text-white bg-gray-900 rounded-lg shadow-sm opacity-0 transition-opacity duration-300 tooltip"
|
||||
>
|
||||
Settings page
|
||||
<div class="tooltip-arrow" data-popper-arrow></div>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
data-dropdown-toggle="language-dropdown"
|
||||
class="inline-flex justify-center p-2 text-gray-500 rounded cursor-pointer dark:hover:text-white dark:text-gray-400 hover:text-gray-900 hover:bg-gray-100 dark:hover:bg-gray-600"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="h-5 w-5 rounded-full mt-0.5"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
viewBox="0 0 3900 3900"
|
||||
>
|
||||
<path fill="#b22234" d="M0 0h7410v3900H0z" />
|
||||
<path
|
||||
d="M0 450h7410m0 600H0m0 600h7410m0 600H0m0 600h7410m0 600H0"
|
||||
stroke="#fff"
|
||||
stroke-width="300"
|
||||
/>
|
||||
<path fill="#3c3b6e" d="M0 0h2964v2100H0z" />
|
||||
<g fill="#fff">
|
||||
<g id="d">
|
||||
<g id="c">
|
||||
<g id="e">
|
||||
<g id="b">
|
||||
<path
|
||||
id="a"
|
||||
d="M247 90l70.534 217.082-184.66-134.164h228.253L176.466 307.082z"
|
||||
/>
|
||||
<use xlink:href="#a" y="420" />
|
||||
<use xlink:href="#a" y="840" />
|
||||
<use xlink:href="#a" y="1260" />
|
||||
</g>
|
||||
<use xlink:href="#a" y="1680" />
|
||||
</g>
|
||||
<use xlink:href="#b" x="247" y="210" />
|
||||
</g>
|
||||
<use xlink:href="#c" x="494" />
|
||||
</g>
|
||||
<use xlink:href="#d" x="988" />
|
||||
<use xlink:href="#c" x="1976" />
|
||||
<use xlink:href="#e" x="2470" />
|
||||
</g>
|
||||
</svg>
|
||||
</button>
|
||||
<!-- Dropdown -->
|
||||
<div
|
||||
class="hidden z-50 my-4 text-base list-none bg-white rounded divide-y divide-gray-100 shadow dark:bg-gray-700"
|
||||
id="language-dropdown"
|
||||
>
|
||||
<ul class="py-1" role="none">
|
||||
<li>
|
||||
<a
|
||||
href="#"
|
||||
class="block py-2 px-4 text-sm text-gray-700 hover:bg-gray-100 dark:hover:text-white dark:text-gray-300 dark:hover:bg-gray-600"
|
||||
role="menuitem"
|
||||
>
|
||||
<div class="inline-flex items-center">
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="h-3.5 w-3.5 rounded-full mr-2"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
id="flag-icon-css-us"
|
||||
viewBox="0 0 512 512"
|
||||
>
|
||||
<g fill-rule="evenodd">
|
||||
<g stroke-width="1pt">
|
||||
<path
|
||||
fill="#bd3d44"
|
||||
d="M0 0h247v10H0zm0 20h247v10H0zm0 20h247v10H0zm0 20h247v10H0zm0 20h247v10H0zm0 20h247v10H0zm0 20h247v10H0z"
|
||||
transform="scale(3.9385)"
|
||||
/>
|
||||
<path
|
||||
fill="#fff"
|
||||
d="M0 10h247v10H0zm0 20h247v10H0zm0 20h247v10H0zm0 20h247v10H0zm0 20h247v10H0zm0 20h247v10H0z"
|
||||
transform="scale(3.9385)"
|
||||
/>
|
||||
</g>
|
||||
<path
|
||||
fill="#192f5d"
|
||||
d="M0 0h98.8v70H0z"
|
||||
transform="scale(3.9385)"
|
||||
/>
|
||||
<path
|
||||
fill="#fff"
|
||||
d="M8.2 3l1 2.8H12L9.7 7.5l.9 2.7-2.4-1.7L6 10.2l.9-2.7-2.4-1.7h3zm16.5 0l.9 2.8h2.9l-2.4 1.7 1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7h2.9zm16.5 0l.9 2.8H45l-2.4 1.7 1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7h2.9zm16.4 0l1 2.8h2.8l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h3zm16.5 0l.9 2.8h2.9l-2.4 1.7 1 2.7L74 8.5l-2.3 1.7.9-2.7-2.4-1.7h2.9zm16.5 0l.9 2.8h2.9L92 7.5l1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7h2.9zm-74.1 7l.9 2.8h2.9l-2.4 1.7 1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7h2.9zm16.4 0l1 2.8h2.8l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h3zm16.5 0l.9 2.8h2.9l-2.4 1.7 1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7h2.9zm16.5 0l.9 2.8h2.9l-2.4 1.7 1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7H65zm16.4 0l1 2.8H86l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h3zm-74 7l.8 2.8h3l-2.4 1.7.9 2.7-2.4-1.7L6 24.2l.9-2.7-2.4-1.7h3zm16.4 0l.9 2.8h2.9l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h2.9zm16.5 0l.9 2.8H45l-2.4 1.7 1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7h2.9zm16.4 0l1 2.8h2.8l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h3zm16.5 0l.9 2.8h2.9l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h2.9zm16.5 0l.9 2.8h2.9L92 21.5l1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7h2.9zm-74.1 7l.9 2.8h2.9l-2.4 1.7 1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7h2.9zm16.4 0l1 2.8h2.8l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h3zm16.5 0l.9 2.8h2.9l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h2.9zm16.5 0l.9 2.8h2.9l-2.4 1.7 1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7H65zm16.4 0l1 2.8H86l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h3zm-74 7l.8 2.8h3l-2.4 1.7.9 2.7-2.4-1.7L6 38.2l.9-2.7-2.4-1.7h3zm16.4 0l.9 2.8h2.9l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h2.9zm16.5 0l.9 2.8H45l-2.4 1.7 1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7h2.9zm16.4 0l1 2.8h2.8l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h3zm16.5 0l.9 2.8h2.9l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h2.9zm16.5 0l.9 2.8h2.9L92 35.5l1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7h2.9zm-74.1 7l.9 2.8h2.9l-2.4 1.7 1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7h2.9zm16.4 0l1 2.8h2.8l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h3zm16.5 0l.9 2.8h2.9l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h2.9zm16.5 0l.9 2.8h2.9l-2.4 1.7 1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7H65zm16.4 0l1 2.8H86l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h3zm-74 7l.8 2.8h3l-2.4 1.7.9 2.7-2.4-1.7L6 52.2l.9-2.7-2.4-1.7h3zm16.4 0l.9 2.8h2.9l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h2.9zm16.5 0l.9 2.8H45l-2.4 1.7 1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7h2.9zm16.4 0l1 2.8h2.8l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h3zm16.5 0l.9 2.8h2.9l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h2.9zm16.5 0l.9 2.8h2.9L92 49.5l1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7h2.9zm-74.1 7l.9 2.8h2.9l-2.4 1.7 1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7h2.9zm16.4 0l1 2.8h2.8l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h3zm16.5 0l.9 2.8h2.9l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h2.9zm16.5 0l.9 2.8h2.9l-2.4 1.7 1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7H65zm16.4 0l1 2.8H86l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h3zm-74 7l.8 2.8h3l-2.4 1.7.9 2.7-2.4-1.7L6 66.2l.9-2.7-2.4-1.7h3zm16.4 0l.9 2.8h2.9l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h2.9zm16.5 0l.9 2.8H45l-2.4 1.7 1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7h2.9zm16.4 0l1 2.8h2.8l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h3zm16.5 0l.9 2.8h2.9l-2.3 1.7.9 2.7-2.4-1.7-2.3 1.7.9-2.7-2.4-1.7h2.9zm16.5 0l.9 2.8h2.9L92 63.5l1 2.7-2.4-1.7-2.4 1.7 1-2.7-2.4-1.7h2.9z"
|
||||
transform="scale(3.9385)"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
English (US)
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#"
|
||||
class="block py-2 px-4 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:text-white dark:hover:bg-gray-600"
|
||||
role="menuitem"
|
||||
>
|
||||
<div class="inline-flex items-center">
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="h-3.5 w-3.5 rounded-full mr-2"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
id="flag-icon-css-de"
|
||||
viewBox="0 0 512 512"
|
||||
>
|
||||
<path fill="#ffce00" d="M0 341.3h512V512H0z" />
|
||||
<path d="M0 0h512v170.7H0z" />
|
||||
<path fill="#d00" d="M0 170.7h512v170.6H0z" />
|
||||
</svg>
|
||||
Deutsch
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#"
|
||||
class="block py-2 px-4 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:text-white dark:hover:bg-gray-600"
|
||||
role="menuitem"
|
||||
>
|
||||
<div class="inline-flex items-center">
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="h-3.5 w-3.5 rounded-full mr-2"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
id="flag-icon-css-it"
|
||||
viewBox="0 0 512 512"
|
||||
>
|
||||
<g fill-rule="evenodd" stroke-width="1pt">
|
||||
<path fill="#fff" d="M0 0h512v512H0z" />
|
||||
<path fill="#009246" d="M0 0h170.7v512H0z" />
|
||||
<path fill="#ce2b37" d="M341.3 0H512v512H341.3z" />
|
||||
</g>
|
||||
</svg>
|
||||
Italiano
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#"
|
||||
class="block py-2 px-4 text-sm text-gray-700 hover:bg-gray-100 dark:hover:text-white dark:text-gray-300 dark:hover:bg-gray-600"
|
||||
role="menuitem"
|
||||
>
|
||||
<div class="inline-flex items-center">
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="h-3.5 w-3.5 rounded-full mr-2"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
id="flag-icon-css-cn"
|
||||
viewBox="0 0 512 512"
|
||||
>
|
||||
<defs>
|
||||
<path
|
||||
id="a"
|
||||
fill="#ffde00"
|
||||
d="M1-.3L-.7.8 0-1 .6.8-1-.3z"
|
||||
/>
|
||||
</defs>
|
||||
<path fill="#de2910" d="M0 0h512v512H0z" />
|
||||
<use
|
||||
width="30"
|
||||
height="20"
|
||||
transform="matrix(76.8 0 0 76.8 128 128)"
|
||||
xlink:href="#a"
|
||||
/>
|
||||
<use
|
||||
width="30"
|
||||
height="20"
|
||||
transform="rotate(-121 142.6 -47) scale(25.5827)"
|
||||
xlink:href="#a"
|
||||
/>
|
||||
<use
|
||||
width="30"
|
||||
height="20"
|
||||
transform="rotate(-98.1 198 -82) scale(25.6)"
|
||||
xlink:href="#a"
|
||||
/>
|
||||
<use
|
||||
width="30"
|
||||
height="20"
|
||||
transform="rotate(-74 272.4 -114) scale(25.6137)"
|
||||
xlink:href="#a"
|
||||
/>
|
||||
<use
|
||||
width="30"
|
||||
height="20"
|
||||
transform="matrix(16 -19.968 19.968 16 256 230.4)"
|
||||
xlink:href="#a"
|
||||
/>
|
||||
</svg>
|
||||
中文 (繁體)
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
11
templates/components/script.html
Normal file
11
templates/components/script.html
Normal file
@@ -0,0 +1,11 @@
|
||||
{% load static %}
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/flowbite/2.3.0/flowbite.min.js"></script>
|
||||
|
||||
<script>
|
||||
// On page load or when changing themes, best to add inline in `head` to avoid FOUC
|
||||
if (localStorage.getItem('color-theme') === 'dark' || (!('color-theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
|
||||
document.documentElement.classList.add('dark');
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark')
|
||||
}
|
||||
</script>
|
||||
7
templates/components/seo.html
Normal file
7
templates/components/seo.html
Normal file
@@ -0,0 +1,7 @@
|
||||
{% load static %}
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="@iTKeyS">
|
||||
<meta name="generator" content="">
|
||||
2
templates/headers.html
Normal file
2
templates/headers.html
Normal file
@@ -0,0 +1,2 @@
|
||||
<section>
|
||||
</section>
|
||||
6
templates/icons/burger.html
Normal file
6
templates/icons/burger.html
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg aria-hidden="true" class="w-6 h-6" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h6a1 1 0 110 2H4a1 1 0 01-1-1zM3 15a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z" clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
<svg aria-hidden="true" class="hidden w-6 h-6" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" >
|
||||
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd" ></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 716 B |
3
templates/icons/notifications.html
Normal file
3
templates/icons/notifications.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg aria-hidden="true" class="w-6 h-6" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10 2a6 6 0 00-6 6v3.586l-.707.707A1 1 0 004 14h12a1 1 0 00.707-1.707L16 11.586V8a6 6 0 00-6-6zM10 18a3 3 0 01-3-3h6a3 3 0 01-3 3z"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 275 B |
1
templates/icons/search.html
Normal file
1
templates/icons/search.html
Normal file
@@ -0,0 +1 @@
|
||||
<svg class="w-4 h-4 text-gray-500 dark:text-gray-400" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 20 20"> <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z"/> </svg>
|
||||
|
After Width: | Height: | Size: 290 B |
58
templates/index.html
Normal file
58
templates/index.html
Normal file
@@ -0,0 +1,58 @@
|
||||
{% extends "components/_base.html" %}
|
||||
{% load static %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<main class="p-4 md:ml-64 h-auto pt-20">
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-4">
|
||||
<div
|
||||
class="border-2 border-dashed border-gray-300 rounded-lg dark:border-gray-600 h-32 md:h-64"
|
||||
></div>
|
||||
<div
|
||||
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-32 md:h-64"
|
||||
></div>
|
||||
<div
|
||||
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-32 md:h-64"
|
||||
></div>
|
||||
<div
|
||||
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-32 md:h-64"
|
||||
></div>
|
||||
</div>
|
||||
<div
|
||||
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-96 mb-4"
|
||||
></div>
|
||||
<div class="grid grid-cols-2 gap-4 mb-4">
|
||||
<div
|
||||
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-48 md:h-72"
|
||||
></div>
|
||||
<div
|
||||
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-48 md:h-72"
|
||||
></div>
|
||||
<div
|
||||
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-48 md:h-72"
|
||||
></div>
|
||||
<div
|
||||
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-48 md:h-72"
|
||||
></div>
|
||||
</div>
|
||||
<div
|
||||
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-96 mb-4"
|
||||
></div>
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div
|
||||
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-48 md:h-72"
|
||||
></div>
|
||||
<div
|
||||
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-48 md:h-72"
|
||||
></div>
|
||||
<div
|
||||
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-48 md:h-72"
|
||||
></div>
|
||||
<div
|
||||
class="border-2 border-dashed rounded-lg border-gray-300 dark:border-gray-600 h-48 md:h-72"
|
||||
></div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
{% endblock content %}
|
||||
3
templates/welcome.html
Normal file
3
templates/welcome.html
Normal file
@@ -0,0 +1,3 @@
|
||||
{% load static %}
|
||||
<section>
|
||||
</section>
|
||||
Reference in New Issue
Block a user