Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e4a894ae7f | |||
| 910c0753af | |||
| 5c64e1f3b9 | |||
| 0a8b3773f5 | |||
| 3bec09dab8 | |||
| 57776be500 | |||
| 25559cd1b8 | |||
| 78251bbcda | |||
| 0867866f00 | |||
| 1c037c4b6f | |||
| 817f4c3e3f | |||
| 6aa1df0288 | |||
| e3de361f8c | |||
| 01e5632856 | |||
| a3b2889f2d | |||
| 440560d91d | |||
| bc5d31e64a | |||
| bf715ceb02 | |||
| 45c0bbad2e | |||
| c0f48eae12 | |||
| c3d39ba55b | |||
| 3fa3766356 | |||
| 04d4e83d1f |
@@ -34,7 +34,6 @@ jobs:
|
||||
run: pip install -r backend/requirements/dev.txt
|
||||
- name: Lint with ruff
|
||||
run: cd backend && ruff check .
|
||||
continue-on-error: true
|
||||
|
||||
testing:
|
||||
runs-on: self-hosted
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
.DS_Store
|
||||
@@ -1 +1,3 @@
|
||||
Dockerfile
|
||||
# Folders
|
||||
venv/
|
||||
__pycache__/
|
||||
|
||||
@@ -1 +1 @@
|
||||
# SkillHub Backend
|
||||
# SkillHub Backend folder
|
||||
|
||||
@@ -3,4 +3,4 @@ from django.apps import AppConfig
|
||||
|
||||
class CoreConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "api.core"
|
||||
name = "core"
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
from django.db import models
|
||||
|
||||
|
||||
class BaseModel(models.Model):
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
class AbstractTag(models.Model):
|
||||
name = models.CharField(
|
||||
max_length=255,
|
||||
unique=True,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
# Generated by Django 4.2.11 on 2024-04-02 21:07
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('users', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Event',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('updated_at', models.DateTimeField(auto_now=True)),
|
||||
('title', models.CharField(max_length=255)),
|
||||
('start_date', models.DateField(blank=True, null=True)),
|
||||
('end_date', models.DateField(blank=True, null=True)),
|
||||
('description', models.TextField(default='')),
|
||||
('is_online', models.BooleanField(default=True)),
|
||||
('location', models.CharField(default='', max_length=512)),
|
||||
('limitation', models.CharField(choices=[('Everyone', 'everyone'), ('School', 'school'), ('Student', 'student'), ('Professional', 'professional')], default='everyone', max_length=64)),
|
||||
('tree', models.JSONField()),
|
||||
('users', models.ManyToManyField(blank=True, related_name='events', to='users.user')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -1,59 +0,0 @@
|
||||
from django.db import models
|
||||
|
||||
from api.core.models import BaseModel
|
||||
|
||||
|
||||
class Event(BaseModel):
|
||||
LIMITATIONS = (
|
||||
("Everyone", "everyone"),
|
||||
("School", "school"),
|
||||
("Student", "student"),
|
||||
("Professional", "professional"),
|
||||
)
|
||||
|
||||
title = models.CharField(
|
||||
max_length=255,
|
||||
)
|
||||
|
||||
users = models.ManyToManyField(
|
||||
"users.User",
|
||||
related_name="events",
|
||||
blank=True,
|
||||
)
|
||||
|
||||
start_date = models.DateField(
|
||||
null=True,
|
||||
blank=True,
|
||||
)
|
||||
|
||||
end_date = models.DateField(
|
||||
null=True,
|
||||
blank=True,
|
||||
)
|
||||
|
||||
description = models.TextField(
|
||||
default="",
|
||||
)
|
||||
|
||||
is_online = models.BooleanField(
|
||||
default=True,
|
||||
)
|
||||
|
||||
location = models.CharField(
|
||||
max_length=512,
|
||||
default="",
|
||||
)
|
||||
|
||||
limitation = models.CharField(
|
||||
max_length=64,
|
||||
choices=LIMITATIONS,
|
||||
default="everyone",
|
||||
)
|
||||
|
||||
tree = models.JSONField()
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
|
||||
def run_algorythm(self):
|
||||
pass
|
||||
@@ -1,9 +0,0 @@
|
||||
from rest_framework import serializers
|
||||
|
||||
from api.events.models import Event
|
||||
|
||||
|
||||
class EventSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Event
|
||||
fields = "__all__"
|
||||
@@ -1,19 +0,0 @@
|
||||
from django.urls import include, path
|
||||
from rest_framework import routers
|
||||
|
||||
from api.events import views
|
||||
from api.events.views import EventViewSet
|
||||
|
||||
app_name = "events"
|
||||
router = routers.DefaultRouter()
|
||||
router.register("", EventViewSet)
|
||||
|
||||
urlpatterns = [
|
||||
path("", include(router.urls)),
|
||||
path("<event_id>/users/", views.EventUsersApiView.as_view(), name="users"),
|
||||
path(
|
||||
"<event_id>/run_algorythm/",
|
||||
views.RunAlgorythmView.as_view(),
|
||||
name="run_algotythm",
|
||||
),
|
||||
]
|
||||
@@ -1,80 +0,0 @@
|
||||
from collections import deque
|
||||
|
||||
|
||||
def get_teams(event): # noqa: C901, PLR0912
|
||||
members_max = 5
|
||||
min_front = 2
|
||||
min_back = 2
|
||||
|
||||
def bfs(tree):
|
||||
result = []
|
||||
queue = deque([tree])
|
||||
while queue:
|
||||
node = queue.popleft()
|
||||
if isinstance(node, dict):
|
||||
for key, value in node.items():
|
||||
result.append(key)
|
||||
queue.append(value)
|
||||
elif isinstance(node, list):
|
||||
for item in node:
|
||||
if isinstance(item, dict):
|
||||
for key, value in item.items():
|
||||
result.append(key)
|
||||
queue.append(value)
|
||||
elif isinstance(item, int) and item == 1:
|
||||
return result
|
||||
return result
|
||||
|
||||
def sort_and_divide_users(users):
|
||||
sorted_users = dict(
|
||||
sorted(users.items(), key=lambda x: (x[1][1], x[1][2]))
|
||||
)
|
||||
|
||||
frontend_users = {
|
||||
name: skills
|
||||
for name, skills in sorted_users.items()
|
||||
if skills[0] == "Frontend"
|
||||
}
|
||||
backend_users = {
|
||||
name: skills
|
||||
for name, skills in sorted_users.items()
|
||||
if skills[0] == "Backend"
|
||||
}
|
||||
|
||||
return frontend_users, backend_users
|
||||
|
||||
db_users = event.users.all().only("skills", "id")
|
||||
users = {}
|
||||
|
||||
for user in db_users:
|
||||
users[str(user.id)] = tuple(bfs(user.skills)[1:])
|
||||
print(users)
|
||||
frontend_users, backend_users = sort_and_divide_users(users)
|
||||
print(frontend_users, backend_users)
|
||||
teams = []
|
||||
while len(frontend_users) >= min_front and len(backend_users) >= min_back:
|
||||
try:
|
||||
team = []
|
||||
|
||||
for i in range(min_front): # noqa: B007
|
||||
team.append(frontend_users.popitem()) # noqa: PERF401
|
||||
|
||||
for i in range(min_back): # noqa: B007
|
||||
team.append(backend_users.popitem()) # noqa: PERF401
|
||||
|
||||
if len(team) < members_max:
|
||||
for i in range(min_front): # noqa: B007
|
||||
if len(team) >= members_max:
|
||||
break
|
||||
if frontend_users:
|
||||
team.append(frontend_users.popitem())
|
||||
|
||||
for i in range(min_back): # noqa: B007
|
||||
if len(team) >= members_max:
|
||||
break
|
||||
if backend_users:
|
||||
team.append(backend_users.popitem())
|
||||
teams.append(team)
|
||||
except KeyError:
|
||||
pass
|
||||
return teams
|
||||
@@ -1,44 +0,0 @@
|
||||
from rest_framework import status
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from api.events.models import Event
|
||||
from api.events.serializers import EventSerializer
|
||||
from api.events.utils import get_teams
|
||||
from api.users.serializers import UserSerializer
|
||||
|
||||
|
||||
class EventViewSet(ModelViewSet):
|
||||
queryset = Event.objects.all()
|
||||
serializer_class = EventSerializer
|
||||
|
||||
|
||||
class EventUsersApiView(APIView):
|
||||
def get(self, request, event_id): # noqa: ARG002
|
||||
try:
|
||||
event = Event.objects.get(pk=event_id)
|
||||
except Event.DoesNotExist:
|
||||
return Response(
|
||||
{"error": "Event does not exist"},
|
||||
status=status.HTTP_404_NOT_FOUND,
|
||||
)
|
||||
|
||||
users = event.users.all()
|
||||
serializer = UserSerializer(users, many=True)
|
||||
|
||||
return Response(serializer.data)
|
||||
|
||||
|
||||
class RunAlgorythmView(APIView):
|
||||
def post(self, request, event_id): # noqa: ARG002
|
||||
try:
|
||||
event = Event.objects.get(pk=event_id)
|
||||
except Event.DoesNotExist:
|
||||
return Response(
|
||||
{"error": "Event does not exist"},
|
||||
status=status.HTTP_404_NOT_FOUND,
|
||||
)
|
||||
teams = get_teams(event)
|
||||
|
||||
return Response(teams)
|
||||
@@ -0,0 +1,31 @@
|
||||
from django.contrib import admin
|
||||
from notifications import models
|
||||
from notifications.forms import (
|
||||
CreateNotificationAdminForm,
|
||||
EditNotificationAdminForm,
|
||||
)
|
||||
|
||||
|
||||
class NotificationAdmin(admin.ModelAdmin):
|
||||
form = EditNotificationAdminForm
|
||||
add_form = CreateNotificationAdminForm
|
||||
list_display = [
|
||||
models.Notification.title.field.name,
|
||||
models.Notification.user.field.name,
|
||||
models.Notification.content.field.name,
|
||||
models.Notification.read.field.name,
|
||||
models.Notification.created_at.field.name,
|
||||
]
|
||||
|
||||
def get_readonly_fields(self, request, obj=None): # noqa: ARG002
|
||||
if obj:
|
||||
return (
|
||||
*self.readonly_fields,
|
||||
models.Notification.read.field.name,
|
||||
models.Notification.created_at.field.name,
|
||||
)
|
||||
|
||||
return self.readonly_fields
|
||||
|
||||
|
||||
admin.site.register(models.Notification, NotificationAdmin)
|
||||
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class NotificationsConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "notifications"
|
||||
@@ -0,0 +1,22 @@
|
||||
from django import forms
|
||||
from notifications.models import Notification
|
||||
|
||||
|
||||
class EditNotificationAdminForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Notification
|
||||
fields = (
|
||||
model.user.field.name,
|
||||
model.title.field.name,
|
||||
model.content.field.name,
|
||||
)
|
||||
|
||||
|
||||
class CreateNotificationAdminForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Notification
|
||||
fields = (
|
||||
model.user.field.name,
|
||||
model.title.field.name,
|
||||
model.content.field.name,
|
||||
)
|
||||
@@ -0,0 +1,36 @@
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
|
||||
|
||||
class NotificationManager(models.Manager):
|
||||
def by_user(self, user_id):
|
||||
return self.get_queryset().filter(
|
||||
user__id=user_id,
|
||||
)
|
||||
|
||||
|
||||
class Notification(models.Model):
|
||||
user = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL,
|
||||
on_delete=models.CASCADE,
|
||||
related_name="notifications",
|
||||
)
|
||||
title = models.CharField(
|
||||
max_length=150,
|
||||
null=False,
|
||||
)
|
||||
content = models.TextField(
|
||||
verbose_name="content",
|
||||
null=False,
|
||||
)
|
||||
read = models.BooleanField(
|
||||
default=False,
|
||||
)
|
||||
created_at = models.DateTimeField(
|
||||
auto_now_add=True,
|
||||
)
|
||||
|
||||
objects = NotificationManager()
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
@@ -0,0 +1,8 @@
|
||||
from notifications.models import Notification
|
||||
from rest_framework import serializers
|
||||
|
||||
|
||||
class NotificationSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Notification
|
||||
fields = ["title", "content", "read", "created_at"]
|
||||
@@ -0,0 +1,13 @@
|
||||
from notifications.models import Notification
|
||||
from notifications.serializers import NotificationSerializer
|
||||
from rest_framework import generics
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
|
||||
|
||||
class UserNotificationsAPIView(generics.ListAPIView):
|
||||
serializer_class = NotificationSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get_queryset(self):
|
||||
user = self.request.user
|
||||
return Notification.objects.by_user(user.id)
|
||||
@@ -1,6 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class EventsConfig(AppConfig):
|
||||
class PingConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "api.events"
|
||||
name = "api.ping"
|
||||
@@ -0,0 +1,7 @@
|
||||
from django.urls import path
|
||||
|
||||
import api.ping.views
|
||||
|
||||
urlpatterns = [
|
||||
path("", api.ping.views.PingApiView.as_view(), name="ping"),
|
||||
]
|
||||
@@ -0,0 +1,9 @@
|
||||
from rest_framework import status
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
|
||||
|
||||
class PingApiView(APIView):
|
||||
def get(self, request): # noqa: ARG002
|
||||
data = "ok"
|
||||
return Response(data, status=status.HTTP_200_OK)
|
||||
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class TeamsConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "teams"
|
||||
@@ -0,0 +1,45 @@
|
||||
# Generated by Django 4.2.11 on 2024-03-31 19:06
|
||||
|
||||
from django.conf import settings
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('users', '0002_rename_technologies_user_skills'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Vacancy',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255, verbose_name='название вакансии')),
|
||||
('start_date', models.DateField(blank=True, null=True, verbose_name='дата начала диапазона возраста участников')),
|
||||
('end_date', models.DateField(blank=True, null=True, verbose_name='дата конец диапазона возраста участников')),
|
||||
('skills', models.ManyToManyField(blank=True, to='users.skill', verbose_name='Технологии')),
|
||||
('specialization', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='users.specialization', verbose_name='специализация')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Team',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('description', models.TextField(verbose_name='описание команды')),
|
||||
('name', models.CharField(max_length=255, verbose_name='название команды')),
|
||||
('avatar', models.ImageField(blank=True, upload_to='teams_avatars', verbose_name='аватарка')),
|
||||
('count_of_members', models.IntegerField(null=True, validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxLengthValidator(5)], verbose_name='количество участников')),
|
||||
('country', models.CharField(blank=True, max_length=255, verbose_name='страна')),
|
||||
('city', models.CharField(blank=True, max_length=255, verbose_name='город')),
|
||||
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='teams', to=settings.AUTH_USER_MODEL)),
|
||||
('members', models.ManyToManyField(to=settings.AUTH_USER_MODEL, verbose_name='участники')),
|
||||
('vacancies', models.ManyToManyField(to='teams.vacancy', verbose_name='вакансии')),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,78 @@
|
||||
from django.core import validators
|
||||
from django.db import models
|
||||
|
||||
from api.users.models import Skill, Specialization, User
|
||||
|
||||
|
||||
class Vacancy(models.Model):
|
||||
name = models.CharField(
|
||||
max_length=255,
|
||||
)
|
||||
age_restriction = models.DateField(
|
||||
blank=True,
|
||||
null=True,
|
||||
)
|
||||
specialization = models.ForeignKey(
|
||||
Specialization,
|
||||
on_delete=models.CASCADE,
|
||||
blank=True,
|
||||
null=True,
|
||||
)
|
||||
skills = models.ManyToManyField(
|
||||
Skill,
|
||||
blank=True,
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class Team(models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
description = models.TextField()
|
||||
|
||||
members = models.ManyToManyField(
|
||||
User,
|
||||
blank=True,
|
||||
unique=True,
|
||||
)
|
||||
|
||||
vacancies = models.ManyToManyField(
|
||||
Vacancy,
|
||||
blank=True,
|
||||
unique=True,
|
||||
)
|
||||
|
||||
avatar = models.ImageField(
|
||||
upload_to="teams_avatars",
|
||||
blank=True,
|
||||
)
|
||||
|
||||
count_of_members = models.IntegerField(
|
||||
validators=[
|
||||
validators.MinValueValidator(1),
|
||||
validators.MaxLengthValidator(5),
|
||||
],
|
||||
verbose_name="количество участников",
|
||||
null=True,
|
||||
)
|
||||
|
||||
country = models.CharField(
|
||||
blank=True,
|
||||
max_length=255,
|
||||
verbose_name="страна",
|
||||
)
|
||||
|
||||
city = models.CharField(
|
||||
blank=True,
|
||||
max_length=255,
|
||||
verbose_name="город",
|
||||
)
|
||||
|
||||
author = models.ForeignKey(
|
||||
User,
|
||||
on_delete=models.CASCADE,
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
@@ -0,0 +1,8 @@
|
||||
from rest_framework import serializers
|
||||
from teams.models import Team
|
||||
|
||||
|
||||
class TeamSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Team
|
||||
fields = ["id", "name", "description"]
|
||||
@@ -0,0 +1,11 @@
|
||||
from django.urls import path
|
||||
|
||||
from .views import AddUserToTeam
|
||||
|
||||
urlpatterns = [
|
||||
path(
|
||||
"add_user_to_team/<int:team_id>/<int:user_id>/",
|
||||
AddUserToTeam.as_view(),
|
||||
name="add_user_to_team",
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,26 @@
|
||||
from backend.project.users.models import User
|
||||
from rest_framework import status
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
from teams.models import Team
|
||||
|
||||
from .serializers import TeamSerializer
|
||||
|
||||
|
||||
class AddUserToTeam(APIView):
|
||||
def post(self, request, team_id, user_id): # noqa: ARG002
|
||||
try:
|
||||
team = Team.objects.get(id=team_id)
|
||||
user = User.objects.get(id=user_id)
|
||||
except Team.DoesNotExist:
|
||||
return Response(
|
||||
{"error": "Team not found"}, status=status.HTTP_404_NOT_FOUND
|
||||
)
|
||||
except User.DoesNotExist:
|
||||
return Response(
|
||||
{"error": "User not found"}, status=status.HTTP_404_NOT_FOUND
|
||||
)
|
||||
|
||||
team.members.add(user)
|
||||
team_serializer = TeamSerializer(team)
|
||||
return Response(team_serializer.data, status=status.HTTP_200_OK)
|
||||
@@ -1,32 +1,6 @@
|
||||
from django.contrib import admin
|
||||
from django.urls import include, path
|
||||
from drf_yasg import openapi
|
||||
from drf_yasg.views import get_schema_view
|
||||
|
||||
schema_view = get_schema_view(
|
||||
openapi.Info(title="SkillHub API", default_version="1")
|
||||
)
|
||||
|
||||
urlpatterns = [
|
||||
# Built-in views
|
||||
path("admin/", admin.site.urls),
|
||||
# API documentation
|
||||
path(
|
||||
"swagger/",
|
||||
schema_view.with_ui("swagger"),
|
||||
name="swagger",
|
||||
),
|
||||
path(
|
||||
"redoc/",
|
||||
schema_view.with_ui("redoc"),
|
||||
name="redoc",
|
||||
),
|
||||
path(
|
||||
"users/",
|
||||
include("api.users.urls", namespace="users"),
|
||||
),
|
||||
path(
|
||||
"events/",
|
||||
include("api.events.urls", namespace="events"),
|
||||
),
|
||||
path("ping", include("api.ping.urls")),
|
||||
path("auth", include("api.users.urls")),
|
||||
]
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
from django.contrib import admin
|
||||
|
||||
from api.users.models import User
|
||||
|
||||
admin.site.register(User)
|
||||
@@ -0,0 +1,51 @@
|
||||
import bcrypt
|
||||
import jwt
|
||||
from django.conf import settings
|
||||
from rest_framework.authentication import (
|
||||
BaseAuthentication,
|
||||
)
|
||||
from rest_framework.exceptions import AuthenticationFailed, NotAuthenticated
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
|
||||
from api.users.models import User
|
||||
|
||||
|
||||
class JWTAuthentication(BaseAuthentication):
|
||||
def authenticate_header(self, request): # noqa: ARG002
|
||||
return "Provide a valid token in the 'Authorization' header"
|
||||
|
||||
def authenticate(self, request):
|
||||
if IsAuthenticated not in getattr(
|
||||
request.resolver_match.func.cls, "permission_classes", []
|
||||
):
|
||||
return None
|
||||
|
||||
token = request.headers.get("Authorization", "").split("Bearer ")[-1]
|
||||
|
||||
if not token:
|
||||
raise NotAuthenticated
|
||||
|
||||
try:
|
||||
payload = jwt.decode(
|
||||
token, settings.SECRET_KEY, algorithms=["HS256"]
|
||||
)
|
||||
|
||||
user = User.objects.get(id=payload["id"])
|
||||
|
||||
if not bcrypt.checkpw(
|
||||
payload["password"].encode("utf-8"),
|
||||
user.password.encode("utf-8"),
|
||||
):
|
||||
error = "Token has expired"
|
||||
raise AuthenticationFailed(error)
|
||||
except User.DoesNotExist:
|
||||
error = "Invalid token"
|
||||
raise AuthenticationFailed(error) from None
|
||||
except jwt.ExpiredSignatureError:
|
||||
error = "Token has expired"
|
||||
raise AuthenticationFailed(error) from None
|
||||
except jwt.InvalidTokenError:
|
||||
error = "Invalid token"
|
||||
raise AuthenticationFailed(error) from None
|
||||
else:
|
||||
return (user, None)
|
||||
@@ -1,6 +1,12 @@
|
||||
# Generated by Django 4.2.11 on 2024-04-02 17:05
|
||||
# Generated by Django 4.2.11 on 2024-04-01 01:58
|
||||
|
||||
import api.users.models
|
||||
import django.contrib.auth.models
|
||||
import django.contrib.auth.validators
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
@@ -8,24 +14,225 @@ class Migration(migrations.Migration):
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
("auth", "0012_alter_user_first_name_max_length"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='User',
|
||||
name="Achievements",
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('updated_at', models.DateTimeField(auto_now=True)),
|
||||
('first_name', models.CharField(max_length=255)),
|
||||
('last_name', models.CharField(max_length=255)),
|
||||
('email', models.EmailField(max_length=254)),
|
||||
('birth_date', models.DateTimeField()),
|
||||
('bio', models.TextField()),
|
||||
('skills', models.JSONField(default=dict)),
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"file",
|
||||
models.FileField(
|
||||
upload_to=api.users.models.Achievements.get_file_path
|
||||
),
|
||||
),
|
||||
("info", models.TextField(max_length=255)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="Skill",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("name", models.CharField(max_length=255, unique=True)),
|
||||
(
|
||||
"level",
|
||||
models.IntegerField(
|
||||
validators=[
|
||||
django.core.validators.MinValueValidator(1),
|
||||
django.core.validators.MaxValueValidator(10),
|
||||
]
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
"abstract": False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="Specialization",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("name", models.CharField(max_length=255, unique=True)),
|
||||
],
|
||||
options={
|
||||
"abstract": False,
|
||||
},
|
||||
),
|
||||
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")),
|
||||
(
|
||||
"last_login",
|
||||
models.DateTimeField(
|
||||
blank=True, null=True, verbose_name="last login"
|
||||
),
|
||||
),
|
||||
(
|
||||
"is_superuser",
|
||||
models.BooleanField(
|
||||
default=False,
|
||||
help_text="Designates that this user has all permissions without explicitly assigning them.",
|
||||
verbose_name="superuser status",
|
||||
),
|
||||
),
|
||||
(
|
||||
"username",
|
||||
models.CharField(
|
||||
error_messages={
|
||||
"unique": "A user with that username already exists."
|
||||
},
|
||||
help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.",
|
||||
max_length=150,
|
||||
unique=True,
|
||||
validators=[
|
||||
django.contrib.auth.validators.UnicodeUsernameValidator()
|
||||
],
|
||||
verbose_name="username",
|
||||
),
|
||||
),
|
||||
(
|
||||
"first_name",
|
||||
models.CharField(
|
||||
blank=True, max_length=150, verbose_name="first name"
|
||||
),
|
||||
),
|
||||
(
|
||||
"last_name",
|
||||
models.CharField(
|
||||
blank=True, max_length=150, verbose_name="last name"
|
||||
),
|
||||
),
|
||||
(
|
||||
"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",
|
||||
),
|
||||
),
|
||||
(
|
||||
"date_joined",
|
||||
models.DateTimeField(
|
||||
default=django.utils.timezone.now, verbose_name="date joined"
|
||||
),
|
||||
),
|
||||
("email", models.EmailField(max_length=254, unique=True)),
|
||||
("birthday", models.DateField(blank=True, null=True)),
|
||||
(
|
||||
"avatar",
|
||||
models.ImageField(
|
||||
max_length=200,
|
||||
null=True,
|
||||
upload_to=api.users.models.User.get_file_path,
|
||||
),
|
||||
),
|
||||
("country", models.TextField(blank=True)),
|
||||
("city", models.TextField(blank=True)),
|
||||
(
|
||||
"experience",
|
||||
models.IntegerField(
|
||||
null=True,
|
||||
validators=[
|
||||
django.core.validators.MinValueValidator(0),
|
||||
django.core.validators.MinValueValidator(100),
|
||||
],
|
||||
),
|
||||
),
|
||||
(
|
||||
"bio",
|
||||
models.TextField(
|
||||
blank=True,
|
||||
validators=[django.core.validators.MaxLengthValidator(512)],
|
||||
),
|
||||
),
|
||||
(
|
||||
"achievements",
|
||||
models.ManyToManyField(blank=True, to="users.achievements"),
|
||||
),
|
||||
(
|
||||
"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",
|
||||
),
|
||||
),
|
||||
("skills", models.ManyToManyField(blank=True, to="users.skill")),
|
||||
(
|
||||
"specialization",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
to="users.specialization",
|
||||
),
|
||||
),
|
||||
(
|
||||
"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,
|
||||
},
|
||||
managers=[
|
||||
("objects", django.contrib.auth.models.UserManager()),
|
||||
],
|
||||
),
|
||||
]
|
||||
|
||||
@@ -1,15 +1,94 @@
|
||||
import uuid
|
||||
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
from django.core import validators
|
||||
from django.db import models
|
||||
|
||||
from api.core.models import BaseModel
|
||||
from api.core.models import AbstractTag
|
||||
|
||||
|
||||
class User(BaseModel):
|
||||
first_name = models.CharField(max_length=255)
|
||||
last_name = models.CharField(max_length=255)
|
||||
email = models.EmailField()
|
||||
birth_date = models.DateTimeField()
|
||||
bio = models.TextField()
|
||||
skills = models.JSONField(default=dict)
|
||||
class Skill(AbstractTag):
|
||||
level = models.IntegerField(
|
||||
validators=[
|
||||
validators.MinValueValidator(1),
|
||||
validators.MaxValueValidator(10),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
class Achievements(models.Model):
|
||||
def get_file_path(self, filename):
|
||||
folder_name = str(uuid.uuid4())
|
||||
return f"achievements/{folder_name}/{filename}"
|
||||
|
||||
file = models.FileField( # noqa: DJ012
|
||||
upload_to=get_file_path,
|
||||
)
|
||||
info = models.TextField(
|
||||
max_length=255,
|
||||
)
|
||||
|
||||
def __str__(self): # noqa: DJ012
|
||||
return self.info
|
||||
|
||||
|
||||
class Specialization(AbstractTag):
|
||||
pass
|
||||
|
||||
|
||||
class User(AbstractUser):
|
||||
def get_file_path(self, filename):
|
||||
folder_name = str(uuid.uuid4())
|
||||
return f"avatars/{folder_name}/{filename}"
|
||||
|
||||
email = models.EmailField(unique=True)
|
||||
birthday = models.DateField(
|
||||
blank=True,
|
||||
null=True,
|
||||
)
|
||||
avatar = models.ImageField(
|
||||
upload_to=get_file_path,
|
||||
max_length=200,
|
||||
null=True,
|
||||
)
|
||||
country = models.TextField(
|
||||
blank=True,
|
||||
)
|
||||
city = models.TextField(
|
||||
blank=True,
|
||||
)
|
||||
experience = models.IntegerField(
|
||||
validators=[
|
||||
validators.MinValueValidator(0),
|
||||
validators.MinValueValidator(100),
|
||||
],
|
||||
null=True,
|
||||
)
|
||||
bio = models.TextField(
|
||||
blank=True,
|
||||
validators=[
|
||||
validators.MaxLengthValidator(
|
||||
512,
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
skills = models.ManyToManyField(
|
||||
Skill,
|
||||
blank=True,
|
||||
)
|
||||
|
||||
achievements = models.ManyToManyField(
|
||||
Achievements,
|
||||
blank=True,
|
||||
)
|
||||
|
||||
specialization = models.ForeignKey(
|
||||
Specialization,
|
||||
on_delete=models.SET_NULL,
|
||||
blank=True,
|
||||
null=True,
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.first_name} {self.last_name}"
|
||||
return self.username
|
||||
|
||||
@@ -1,24 +1,79 @@
|
||||
from django.contrib.auth.password_validation import validate_password
|
||||
from rest_framework import serializers
|
||||
|
||||
from api.events.models import Event
|
||||
from api.users.models import User
|
||||
|
||||
|
||||
class UserSerializer(serializers.ModelSerializer):
|
||||
event = serializers.IntegerField(write_only=True)
|
||||
|
||||
class UserRegistrationSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = User
|
||||
fields = "__all__"
|
||||
fields = [
|
||||
"first_name",
|
||||
"last_name",
|
||||
"username",
|
||||
"email",
|
||||
"password",
|
||||
"country",
|
||||
"city",
|
||||
]
|
||||
|
||||
def create(self, validated_data):
|
||||
try:
|
||||
event = Event.objects.get(pk=validated_data.pop("event"))
|
||||
except Event.DoesNotExist as e:
|
||||
msg = "Event does not exist"
|
||||
raise serializers.ValidationError(msg) from e
|
||||
def validate_password(self, value):
|
||||
validate_password(value)
|
||||
|
||||
user = User.objects.create(**validated_data)
|
||||
event.users.add(user)
|
||||
return value
|
||||
|
||||
return user
|
||||
|
||||
class UserLoginSerializer(serializers.Serializer):
|
||||
remember_me = serializers.BooleanField(default=False, required=False)
|
||||
username = serializers.CharField()
|
||||
password = serializers.CharField()
|
||||
|
||||
|
||||
class UserProfileSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = User
|
||||
fields = (
|
||||
"first_name",
|
||||
"last_name",
|
||||
"username",
|
||||
"email",
|
||||
"birthday",
|
||||
"country",
|
||||
"city",
|
||||
"bio",
|
||||
"avatar",
|
||||
"experience",
|
||||
"specialization",
|
||||
"achievements",
|
||||
"skills",
|
||||
)
|
||||
|
||||
|
||||
class UpdateProfileSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = User
|
||||
fields = [
|
||||
"countryCode",
|
||||
"isPublic",
|
||||
"phone",
|
||||
"image",
|
||||
]
|
||||
|
||||
def to_representation(self, instance):
|
||||
data = super().to_representation(instance)
|
||||
if data["image"] is None:
|
||||
del data["image"]
|
||||
if data["phone"] is None:
|
||||
del data["phone"]
|
||||
return data
|
||||
|
||||
|
||||
class PasswordChangeSerializer(serializers.Serializer):
|
||||
# ruff: noqa: N815
|
||||
old_password = serializers.CharField(required=True)
|
||||
new_password = serializers.CharField(required=True)
|
||||
|
||||
def validate_password(self, value):
|
||||
validate_password(value)
|
||||
|
||||
return value
|
||||
|
||||
@@ -1,28 +1,26 @@
|
||||
from django.urls import include, path
|
||||
from rest_framework import routers
|
||||
|
||||
from api.users.views import (
|
||||
DownloadUsersFromExcelView,
|
||||
RegisterUsersFromExcelView,
|
||||
UserViewSet,
|
||||
)
|
||||
|
||||
app_name = "users"
|
||||
|
||||
router = routers.DefaultRouter()
|
||||
router.register("", UserViewSet)
|
||||
from django.urls import path
|
||||
|
||||
import api.users.views
|
||||
|
||||
urlpatterns = [
|
||||
path("", include(router.urls)),
|
||||
path(
|
||||
"upload/excel/<event_id>/",
|
||||
RegisterUsersFromExcelView.as_view(),
|
||||
name="excel-upload",
|
||||
"/sign-up/",
|
||||
api.users.views.SignupUserApiView.as_view(),
|
||||
name="sign-up",
|
||||
),
|
||||
path(
|
||||
"download/excel/<event_id>/",
|
||||
DownloadUsersFromExcelView.as_view(),
|
||||
name="excel-download",
|
||||
"/sign-in/",
|
||||
api.users.views.SigninUserApiView.as_view(),
|
||||
name="sign-in",
|
||||
),
|
||||
path(
|
||||
"/me/profile/",
|
||||
api.users.views.ProfileMeApiView.as_view(),
|
||||
name="profile-me",
|
||||
),
|
||||
path(
|
||||
"/me/updatePassword/",
|
||||
api.users.views.PasswordChangeApiView.as_view(),
|
||||
name="password-change",
|
||||
),
|
||||
]
|
||||
|
||||
@@ -1,81 +1,131 @@
|
||||
import io
|
||||
from datetime import timedelta
|
||||
|
||||
import pandas as pd
|
||||
from django.http import FileResponse
|
||||
import bcrypt
|
||||
import jwt
|
||||
from django.conf import settings
|
||||
from django.utils import timezone
|
||||
from rest_framework import status
|
||||
from rest_framework.exceptions import (
|
||||
NotAuthenticated,
|
||||
PermissionDenied,
|
||||
ValidationError,
|
||||
)
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from api.events.models import Event
|
||||
from api.users.models import User
|
||||
from api.users.serializers import UserSerializer
|
||||
from api.users.serializers import (
|
||||
PasswordChangeSerializer,
|
||||
UpdateProfileSerializer,
|
||||
UserLoginSerializer,
|
||||
UserProfileSerializer,
|
||||
UserRegistrationSerializer,
|
||||
)
|
||||
|
||||
|
||||
class UserViewSet(ModelViewSet):
|
||||
queryset = User.objects.all()
|
||||
serializer_class = UserSerializer
|
||||
class SignupUserApiView(APIView):
|
||||
def post(self, request):
|
||||
serializer = UserRegistrationSerializer(data=request.data)
|
||||
|
||||
if serializer.is_valid():
|
||||
password = serializer.validated_data["password"]
|
||||
password_hash = bcrypt.hashpw(
|
||||
password.encode("utf-8"), bcrypt.gensalt()
|
||||
).decode("utf-8")
|
||||
serializer.validated_data["password"] = password_hash
|
||||
|
||||
serializer.save()
|
||||
|
||||
return Response("ok", status=status.HTTP_201_CREATED)
|
||||
|
||||
raise ValidationError(serializer.errors)
|
||||
|
||||
|
||||
class RegisterUsersFromExcelView(APIView):
|
||||
def post(self, request, event_id):
|
||||
try:
|
||||
event = Event.objects.get(pk=event_id)
|
||||
except Event.DoesNotExist:
|
||||
return Response(
|
||||
{"error": "Event does not exist"},
|
||||
status=status.HTTP_404_NOT_FOUND,
|
||||
)
|
||||
class SigninUserApiView(APIView):
|
||||
def post(self, request):
|
||||
serializer = UserLoginSerializer(data=request.data)
|
||||
|
||||
excel_file = request.FILES.get("excel_file")
|
||||
if excel_file is None:
|
||||
return Response(
|
||||
{"error": "No Excel file provided"},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
if not serializer.is_valid():
|
||||
raise ValidationError(serializer.errors)
|
||||
|
||||
try:
|
||||
data = pd.read_excel(excel_file)
|
||||
username = serializer.validated_data.get("username")
|
||||
password = serializer.validated_data.get("password")
|
||||
|
||||
for _, row in data.iterrows():
|
||||
user = User.objects.create(
|
||||
first_name=row["first_name"],
|
||||
last_name=row["last_name"],
|
||||
email=row["email"],
|
||||
birth_date=row["birth_date"],
|
||||
bio=row["bio"],
|
||||
user = User.objects.filter(username=username).first()
|
||||
|
||||
if user is not None:
|
||||
if not bcrypt.checkpw(
|
||||
password.encode("utf-8"), user.password.encode("utf-8")
|
||||
):
|
||||
raise NotAuthenticated(
|
||||
{"error": "Invalid credentials"},
|
||||
)
|
||||
|
||||
event.users.add(user)
|
||||
|
||||
return Response(
|
||||
{"success": "Users registered successfully"},
|
||||
status=status.HTTP_201_CREATED,
|
||||
else:
|
||||
raise NotAuthenticated(
|
||||
{"error": "Invalid credentials"},
|
||||
)
|
||||
|
||||
except Exception as e: # noqa: BLE001
|
||||
return Response(
|
||||
{"error": str(e)}, status=status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
token = jwt.encode(
|
||||
{
|
||||
"id": user.id,
|
||||
"password": password,
|
||||
"exp": timezone.now() + timedelta(hours=24),
|
||||
},
|
||||
settings.SECRET_KEY,
|
||||
algorithm="HS256",
|
||||
)
|
||||
|
||||
return Response({"token": token})
|
||||
|
||||
|
||||
class DownloadUsersFromExcelView(APIView):
|
||||
def get(self, _, event_id):
|
||||
try:
|
||||
users = Event.objects.get(pk=event_id).users
|
||||
except Event.DoesNotExist:
|
||||
return Response(
|
||||
{"error": "Event does not exist"},
|
||||
status=status.HTTP_404_NOT_FOUND,
|
||||
)
|
||||
class ProfileMeApiView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
serializer = UserSerializer(users, many=True)
|
||||
data = serializer.data
|
||||
def get(self, request):
|
||||
serializer = UserProfileSerializer(request.user)
|
||||
return Response(serializer.data)
|
||||
|
||||
data = pd.DataFrame(data)
|
||||
def patch(self, request):
|
||||
user = request.user
|
||||
serializer = UpdateProfileSerializer(
|
||||
user, data=request.data, partial=True
|
||||
)
|
||||
if serializer.is_valid():
|
||||
errors = User.check_unique(user.id, serializer.validated_data)
|
||||
if errors:
|
||||
return Response(
|
||||
{"reason:": str(errors)}, status=status.HTTP_409_CONFLICT
|
||||
)
|
||||
serializer.save()
|
||||
|
||||
excel_data = io.BytesIO()
|
||||
data.to_excel(excel_data, index=False)
|
||||
excel_data.seek(0)
|
||||
return Response(self._get_profile_data(user))
|
||||
|
||||
return FileResponse(excel_data, filename="users.xlsx")
|
||||
raise ValidationError(serializer.errors)
|
||||
|
||||
|
||||
class PasswordChangeApiView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def post(self, request):
|
||||
serializer = PasswordChangeSerializer(data=request.data)
|
||||
|
||||
if serializer.is_valid():
|
||||
old_password = serializer.validated_data.get("oldPassword")
|
||||
new_password = serializer.validated_data.get("newPassword")
|
||||
|
||||
if bcrypt.checkpw(
|
||||
old_password.encode("utf-8"),
|
||||
request.user.password.encode("utf-8"),
|
||||
):
|
||||
password_hash = bcrypt.hashpw(
|
||||
new_password.encode("utf-8"), bcrypt.gensalt()
|
||||
).decode("utf-8")
|
||||
request.user.password = password_hash
|
||||
request.user.save()
|
||||
|
||||
return Response({"status": "ok"}, status=status.HTTP_200_OK)
|
||||
|
||||
raise PermissionDenied({"error": "Invalid old password"})
|
||||
|
||||
raise ValidationError(serializer.errors)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import os
|
||||
|
||||
from django.core.asgi import get_asgi_application
|
||||
import django.core.asgi
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
|
||||
|
||||
application = get_asgi_application()
|
||||
application = django.core.asgi.get_asgi_application()
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import pathlib
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from environs import Env
|
||||
import environs
|
||||
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
BASE_DIR = pathlib.Path(__file__).resolve().parent.parent
|
||||
|
||||
env = Env()
|
||||
env = environs.Env()
|
||||
env.read_env(BASE_DIR.parent / ".env")
|
||||
|
||||
DEFAULT_HOSTS = ["127.0.0.1", "localhost"]
|
||||
|
||||
with env.prefixed("DJANGO_"):
|
||||
SECRET_KEY = env("SECRET_KEY", "change-me")
|
||||
SECRET_KEY = env("SECRET_KEY", "secret_key")
|
||||
DEBUG = env.bool("DEBUG", True)
|
||||
ALLOWED_HOSTS = env.list("ALLOWED_HOSTS", DEFAULT_HOSTS)
|
||||
INTERNAL_IPS = env.list("INTERNAL_IPS", ALLOWED_HOSTS)
|
||||
@@ -23,7 +23,7 @@ with env.prefixed("POSTGRES_"):
|
||||
POSTGRES_DB = env("DB", "postgres")
|
||||
POSTGRES_USER = env("USER", "postgres")
|
||||
POSTGRES_PASSWORD = env("PASSWORD", "postgres")
|
||||
POSTGRES_HOST = env("HOST", "localhost")
|
||||
POSTGRES_HOST = env("HOST")
|
||||
POSTGRES_PORT = env("PORT", "5432")
|
||||
|
||||
|
||||
@@ -43,17 +43,15 @@ INSTALLED_APPS = [
|
||||
"django.contrib.staticfiles",
|
||||
# Third-party apps
|
||||
"rest_framework",
|
||||
"rest_framework_simplejwt",
|
||||
"corsheaders",
|
||||
"drf_yasg",
|
||||
# Developed apps
|
||||
"api",
|
||||
"api.users",
|
||||
"api.events",
|
||||
"api.ping.apps.PingConfig",
|
||||
"api.users.apps.UsersConfig",
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
"corsheaders.middleware.CorsMiddleware",
|
||||
"django.middleware.common.CommonMiddleware",
|
||||
"django.middleware.security.SecurityMiddleware",
|
||||
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||
"django.middleware.common.CommonMiddleware",
|
||||
@@ -61,6 +59,8 @@ MIDDLEWARE = [
|
||||
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||
"django.contrib.messages.middleware.MessageMiddleware",
|
||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||
"corsheaders.middleware.CorsMiddleware",
|
||||
"django.middleware.common.CommonMiddleware",
|
||||
]
|
||||
|
||||
ROOT_URLCONF = "config.urls"
|
||||
@@ -129,23 +129,33 @@ AUTH_PASSWORD_VALIDATORS = [
|
||||
},
|
||||
]
|
||||
|
||||
USE_I18N = True
|
||||
LANGUAGE_CODE = "en-us"
|
||||
|
||||
TIME_ZONE = "UTC"
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
STATIC_URL = "static/"
|
||||
|
||||
STATIC_ROOT = BASE_DIR / "static"
|
||||
|
||||
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
||||
|
||||
AUTH_USER_MODEL = "users.User"
|
||||
|
||||
REST_FRAMEWORK = {
|
||||
"DEFAULT_FILTER_BACKENDS": [
|
||||
"django_filters.rest_framework.DjangoFilterBackend"
|
||||
],
|
||||
"DEFAULT_AUTHENTICATION_CLASSES": (
|
||||
"api.users.authentication.JWTAuthentication",
|
||||
),
|
||||
}
|
||||
|
||||
APPEND_SLASH = False
|
||||
|
||||
if DEBUG and not (TESTING or MIGRATING):
|
||||
INSTALLED_APPS.append("debug_toolbar")
|
||||
MIDDLEWARE.append("debug_toolbar.middleware.DebugToolbarMiddleware")
|
||||
|
||||
@@ -1,7 +1,44 @@
|
||||
from django.conf import settings
|
||||
from django.contrib import admin
|
||||
from django.urls import include, path
|
||||
from drf_yasg import openapi
|
||||
from drf_yasg.views import get_schema_view
|
||||
from rest_framework import permissions
|
||||
|
||||
schema_view = get_schema_view(
|
||||
openapi.Info(title="SkillHub API", default_version="v1"),
|
||||
public=True,
|
||||
permission_classes=(permissions.AllowAny,),
|
||||
)
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
# Built-in urls
|
||||
path("admin/", admin.site.urls),
|
||||
path(
|
||||
"api-auth/",
|
||||
include(
|
||||
"rest_framework.urls",
|
||||
namespace="rest_framework",
|
||||
),
|
||||
),
|
||||
# API documentation
|
||||
path(
|
||||
"swagger<format>/",
|
||||
schema_view.without_ui(cache_timeout=0),
|
||||
name="schema-json",
|
||||
),
|
||||
path(
|
||||
"swagger/",
|
||||
schema_view.with_ui("swagger", cache_timeout=0),
|
||||
name="schema-swagger-ui",
|
||||
),
|
||||
path(
|
||||
"redoc/",
|
||||
schema_view.with_ui("redoc", cache_timeout=0),
|
||||
name="schema-redoc",
|
||||
),
|
||||
# API
|
||||
path("api/", include("api.urls")),
|
||||
]
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import os
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
import django.core.wsgi
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
|
||||
|
||||
application = get_wsgi_application()
|
||||
application = django.core.wsgi.get_wsgi_application()
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.11 on 2024-03-31 19:06
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('notifications', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='notification',
|
||||
name='content',
|
||||
field=models.TextField(verbose_name='содержание'),
|
||||
),
|
||||
]
|
||||
@@ -1,10 +1,14 @@
|
||||
[tool.ruff]
|
||||
line-length = 79
|
||||
exclude = ["migrations"]
|
||||
indent-width = 4
|
||||
exclude = ["migrations", "venv", ".venv"]
|
||||
|
||||
[tool.ruff.lint]
|
||||
select = ["ALL"]
|
||||
ignore = ["D", "ANN", "EXE002", "RUF012", "RUF001", "COM812", "ISC001"]
|
||||
|
||||
[tool.ruff.format]
|
||||
quote-style = "double"
|
||||
indent-style = "space"
|
||||
skip-magic-trailing-comma = false
|
||||
line-ending = "auto"
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
black
|
||||
sort-requirements
|
||||
ruff==0.3.4
|
||||
django-debug-toolbar==4.3.0
|
||||
|
||||
-r test.txt
|
||||
-r lint.txt
|
||||
|
||||
@@ -1,30 +1,13 @@
|
||||
asgiref==3.8.1
|
||||
Django==4.2.11
|
||||
django-cors-headers==4.3.1
|
||||
django-debug-toolbar==4.3.0
|
||||
django-filter==24.2
|
||||
djangorestframework==3.15.1
|
||||
drf-yasg==1.21.7
|
||||
django==4.2.11
|
||||
environs==11.0.0
|
||||
et-xmlfile==1.1.0
|
||||
gunicorn==21.2.0
|
||||
inflection==0.5.1
|
||||
marshmallow==3.21.1
|
||||
numpy==1.26.4
|
||||
openpyxl==3.1.2
|
||||
packaging==24.0
|
||||
pandas==2.2.1
|
||||
pillow==10.2.0
|
||||
psycopg2-binary==2.9.9
|
||||
python-dateutil==2.9.0.post0
|
||||
python-dotenv==1.0.1
|
||||
pytz==2024.1
|
||||
PyYAML==6.0.1
|
||||
ruff==0.3.5
|
||||
setuptools==69.2.0
|
||||
six==1.16.0
|
||||
sort-requirements==1.3.0
|
||||
sqlparse==0.4.4
|
||||
tzdata==2024.1
|
||||
uritemplate==4.1.1
|
||||
pandas==2.2.1
|
||||
psycopg2-binary==2.9.9
|
||||
djangorestframework==3.15.1
|
||||
djangorestframework-simplejwt==5.3.1
|
||||
django-filter==24.2
|
||||
Pillow==10.2.0
|
||||
drf-yasg==1.21.7
|
||||
django-cors-headers
|
||||
setuptools
|
||||
bcrypt==4.1.2
|
||||
|
||||
@@ -12,7 +12,7 @@ services:
|
||||
environment:
|
||||
POSTGRES_DB: ${POSTGRES_DB:-postgres}
|
||||
POSTGRES_USER: ${POSTGRES_USER:-postgres}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-8gDNJqx2D0hvH35}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres}
|
||||
ports:
|
||||
- "${POSTGRES_PORT:-5432}:5432"
|
||||
volumes:
|
||||
@@ -21,15 +21,15 @@ services:
|
||||
backend:
|
||||
build: ./backend
|
||||
container_name: backend
|
||||
volumes:
|
||||
- media_volume:/app/project/media/
|
||||
- static_volume:/app/project/static/
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
restart: unless-stopped
|
||||
expose:
|
||||
- 8000
|
||||
environment:
|
||||
POSTGRES_USER: ${POSTGRES_USER:-postgres}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-8gDNJqx2D0hvH35}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres}
|
||||
POSTGRES_PORT: ${POSTGRES_PORT:-5432}
|
||||
POSTGRES_DB: ${POSTGRES_DB:-postgres}
|
||||
POSTGRES_HOST: postgres
|
||||
@@ -38,30 +38,18 @@ services:
|
||||
DJANGO_DEBUG: ${DJANGO_DEBUG:-false}
|
||||
DJANGO_ALLOWED_HOSTS: ${DJANGO_ALLOWED_HOSTS:-*}
|
||||
DJANGO_INTERNAL_IPS: ${DJANGO_INTERNAL_IPS:-127.0.0.1}
|
||||
DJANGO_CSRF_TRUSTED_ORIGINS: ${DJANGO_CSRF_TRUSTED_ORIGINS:-https://animulichki.ru}
|
||||
expose:
|
||||
- 8080
|
||||
command:
|
||||
[
|
||||
"sh",
|
||||
"-c",
|
||||
"cd project && python manage.py collectstatic --noinput && python manage.py migrate && gunicorn config.wsgi:application --bind 0.0.0.0:8080",
|
||||
]
|
||||
|
||||
nginx:
|
||||
container_name: nginx
|
||||
command: ["sh", "-c", "cd project && python manage.py migrate && gunicorn config.wsgi:application --bind 0.0.0.0:8080"]
|
||||
ports:
|
||||
- 8080:8080
|
||||
|
||||
frontend:
|
||||
container_name: frontend
|
||||
build:
|
||||
context: ./frontend
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "80:80"
|
||||
volumes:
|
||||
- ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf
|
||||
- ./nginx/.htpasswd:/etc/nginx/.htpasswd
|
||||
- media_volume:/var/html/media/
|
||||
- static_volume:/var/html/static/
|
||||
depends_on:
|
||||
- backend
|
||||
- "3000:3000"
|
||||
restart: always
|
||||
|
||||
pgadmin:
|
||||
image: dpage/pgadmin4:8.4
|
||||
@@ -71,7 +59,7 @@ services:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
PGADMIN_DEFAULT_EMAIL: ${PGADMIN_EMAIL:-admin@mail.com}
|
||||
PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_PASSWORD:-5tGnQhc2hEdb0nj}
|
||||
PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_PASSWORD:-admin}
|
||||
ports:
|
||||
- "${PGADMIN_PORT:-5050}:80"
|
||||
restart: always
|
||||
@@ -80,6 +68,5 @@ services:
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
redis_data:
|
||||
pgadmin_data:
|
||||
media_volume:
|
||||
static_volume:
|
||||
|
||||
@@ -15,3 +15,5 @@ RUN npm run build
|
||||
FROM nginx:stable-alpine3.17-slim
|
||||
|
||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||
|
||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
|
||||
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
@@ -13,8 +12,8 @@
|
||||
--card-foreground: 240 10% 3.9%;
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 240 10% 3.9%;
|
||||
--primary: 142.1 76.2% 36.3%;
|
||||
--primary-foreground: 355.7 100% 97.3%;
|
||||
--primary: 240 5.9% 10%;
|
||||
--primary-foreground: 0 0% 98%;
|
||||
--secondary: 240 4.8% 95.9%;
|
||||
--secondary-foreground: 240 5.9% 10%;
|
||||
--muted: 240 4.8% 95.9%;
|
||||
@@ -25,36 +24,35 @@
|
||||
--destructive-foreground: 0 0% 98%;
|
||||
--border: 240 5.9% 90%;
|
||||
--input: 240 5.9% 90%;
|
||||
--ring: 142.1 76.2% 36.3%;
|
||||
--ring: 240 5.9% 10%;
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: 20 14.3% 4.1%;
|
||||
--foreground: 0 0% 95%;
|
||||
--card: 24 9.8% 10%;
|
||||
--card-foreground: 0 0% 95%;
|
||||
--popover: 0 0% 9%;
|
||||
--popover-foreground: 0 0% 95%;
|
||||
--primary: 142.1 70.6% 45.3%;
|
||||
--primary-foreground: 144.9 80.4% 10%;
|
||||
--background: 240 10% 3.9%;
|
||||
--foreground: 0 0% 98%;
|
||||
--card: 240 10% 3.9%;
|
||||
--card-foreground: 0 0% 98%;
|
||||
--popover: 240 10% 3.9%;
|
||||
--popover-foreground: 0 0% 98%;
|
||||
--primary: 0 0% 98%;
|
||||
--primary-foreground: 240 5.9% 10%;
|
||||
--secondary: 240 3.7% 15.9%;
|
||||
--secondary-foreground: 0 0% 98%;
|
||||
--muted: 0 0% 15%;
|
||||
--muted: 240 3.7% 15.9%;
|
||||
--muted-foreground: 240 5% 64.9%;
|
||||
--accent: 12 6.5% 15.1%;
|
||||
--accent: 240 3.7% 15.9%;
|
||||
--accent-foreground: 0 0% 98%;
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 0 85.7% 97.3%;
|
||||
--destructive-foreground: 0 0% 98%;
|
||||
--border: 240 3.7% 15.9%;
|
||||
--input: 240 3.7% 15.9%;
|
||||
--ring: 142.4 71.8% 29.2%;
|
||||
--ring: 240 4.9% 83.9%;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<link rel="icon" type="image/svg+xml" href="/logo.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="stylesheet" href="globals.css">
|
||||
<title>SkillHub</title>
|
||||
<title>React</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
server {
|
||||
listen 3000;
|
||||
|
||||
location / {
|
||||
root /usr/share/nginx/html/;
|
||||
include /etc/nginx/mime.types;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
}
|
||||
@@ -10,43 +10,31 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@balkangraph/orgchart.js": "^8.14.19",
|
||||
"@hookform/resolvers": "^3.3.4",
|
||||
"@radix-ui/react-accordion": "^1.1.2",
|
||||
"@radix-ui/react-avatar": "^1.0.4",
|
||||
"@radix-ui/react-checkbox": "^1.0.4",
|
||||
"@radix-ui/react-dialog": "^1.0.5",
|
||||
"@radix-ui/react-dropdown-menu": "^2.0.6",
|
||||
"@radix-ui/react-icons": "^1.3.0",
|
||||
"@radix-ui/react-label": "^2.0.2",
|
||||
"@radix-ui/react-menubar": "^1.0.4",
|
||||
"@radix-ui/react-navigation-menu": "^1.1.4",
|
||||
"@radix-ui/react-popover": "^1.0.7",
|
||||
"@radix-ui/react-separator": "^1.0.3",
|
||||
"@radix-ui/react-slot": "^1.0.2",
|
||||
"@radix-ui/react-switch": "^1.0.3",
|
||||
"@radix-ui/react-tabs": "^1.0.4",
|
||||
"@radix-ui/react-toast": "^1.1.5",
|
||||
"@vitejs/plugin-react-swc": "^3.5.0",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.1.0",
|
||||
"cmdk": "^1.0.0",
|
||||
"cn-decorator": "^2.1.0",
|
||||
"cross": "^1.0.0",
|
||||
"i18next": "^23.10.1",
|
||||
"less": "^4.2.0",
|
||||
"lucide-react": "^0.363.0",
|
||||
"moment": "^2.30.1",
|
||||
"next-themes": "^0.3.0",
|
||||
"postcss": "^8.4.38",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-hook-form": "^7.51.2",
|
||||
"react-i18next": "^14.1.0",
|
||||
"react-resizable-panels": "^2.0.16",
|
||||
"react-router": "^6.22.3",
|
||||
"react-router-dom": "^6.22.3",
|
||||
"sonner": "^1.4.41",
|
||||
"tailwind-merge": "^2.2.2",
|
||||
"tailwindcss": "^3.4.3",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
@@ -60,17 +48,13 @@
|
||||
"@types/react-dom": "^18.2.22",
|
||||
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
||||
"@typescript-eslint/parser": "^7.2.0",
|
||||
"@vitejs/plugin-react": "^4.2.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-config-standard-with-typescript": "19.0.1",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-react": "^7.34.1",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.6",
|
||||
"postcss": "^8.4.32",
|
||||
"prettier": "^3.2.5",
|
||||
"tailwindcss": "^3.3.5",
|
||||
"vite": "^5.0.0"
|
||||
"prettier": "^3.2.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
export default {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,125 +0,0 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
/* *=========== Default theme =========== */
|
||||
/* @layer base {
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 222.2 84% 4.9%;
|
||||
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 222.2 84% 4.9%;
|
||||
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 222.2 84% 4.9%;
|
||||
|
||||
--primary: 222.2 47.4% 11.2%;
|
||||
--primary-foreground: 210 40% 98%;
|
||||
|
||||
--secondary: 210 40% 96.1%;
|
||||
--secondary-foreground: 222.2 47.4% 11.2%;
|
||||
|
||||
--muted: 210 40% 96.1%;
|
||||
--muted-foreground: 215.4 16.3% 46.9%;
|
||||
|
||||
--accent: 210 40% 96.1%;
|
||||
--accent-foreground: 222.2 47.4% 11.2%;
|
||||
|
||||
--destructive: 0 84.2% 60.2%;
|
||||
--destructive-foreground: 210 40% 98%;
|
||||
|
||||
--border: 214.3 31.8% 91.4%;
|
||||
--input: 214.3 31.8% 91.4%;
|
||||
--ring: 222.2 84% 4.9%;
|
||||
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: 222.2 84% 4.9%;
|
||||
--foreground: 210 40% 98%;
|
||||
|
||||
--card: 222.2 84% 4.9%;
|
||||
--card-foreground: 210 40% 98%;
|
||||
|
||||
--popover: 222.2 84% 4.9%;
|
||||
--popover-foreground: 210 40% 98%;
|
||||
|
||||
--primary: 210 40% 98%;
|
||||
--primary-foreground: 222.2 47.4% 11.2%;
|
||||
|
||||
--secondary: 217.2 32.6% 17.5%;
|
||||
--secondary-foreground: 210 40% 98%;
|
||||
|
||||
--muted: 217.2 32.6% 17.5%;
|
||||
--muted-foreground: 215 20.2% 65.1%;
|
||||
|
||||
--accent: 217.2 32.6% 17.5%;
|
||||
--accent-foreground: 210 40% 98%;
|
||||
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 210 40% 98%;
|
||||
|
||||
--border: 217.2 32.6% 17.5%;
|
||||
--input: 217.2 32.6% 17.5%;
|
||||
--ring: 212.7 26.8% 83.9%;
|
||||
}
|
||||
} */
|
||||
|
||||
/* *=========== Green theme =========== */
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 240 10% 3.9%;
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 240 10% 3.9%;
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 240 10% 3.9%;
|
||||
--primary: 142.1 76.2% 36.3%;
|
||||
--primary-foreground: 355.7 100% 97.3%;
|
||||
--secondary: 240 4.8% 95.9%;
|
||||
--secondary-foreground: 240 5.9% 10%;
|
||||
--muted: 240 4.8% 95.9%;
|
||||
--muted-foreground: 240 3.8% 46.1%;
|
||||
--accent: 240 4.8% 95.9%;
|
||||
--accent-foreground: 240 5.9% 10%;
|
||||
--destructive: 0 84.2% 60.2%;
|
||||
--destructive-foreground: 0 0% 98%;
|
||||
--border: 240 5.9% 90%;
|
||||
--input: 240 5.9% 90%;
|
||||
--ring: 142.1 76.2% 36.3%;
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: 20 14.3% 4.1%;
|
||||
--foreground: 0 0% 95%;
|
||||
--card: 24 9.8% 10%;
|
||||
--card-foreground: 0 0% 95%;
|
||||
--popover: 0 0% 9%;
|
||||
--popover-foreground: 0 0% 95%;
|
||||
--primary: 142.1 70.6% 45.3%;
|
||||
--primary-foreground: 144.9 80.4% 10%;
|
||||
--secondary: 240 3.7% 15.9%;
|
||||
--secondary-foreground: 0 0% 98%;
|
||||
--muted: 0 0% 15%;
|
||||
--muted-foreground: 240 5% 64.9%;
|
||||
--accent: 12 6.5% 15.1%;
|
||||
--accent-foreground: 0 0% 98%;
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 0 85.7% 97.3%;
|
||||
--border: 240 3.7% 15.9%;
|
||||
--input: 240 3.7% 15.9%;
|
||||
--ring: 142.4 71.8% 29.2%;
|
||||
}
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
}
|
||||
@@ -7,60 +7,37 @@ import {
|
||||
} from "react-router-dom";
|
||||
import Landing from "./components/pages/Landing/Landing";
|
||||
import Main from "./components/pages/Main/Main";
|
||||
import Successful from "./components/pages/Successful/Successful";
|
||||
import AdminPage from "./components/pages/Admin/Admin";
|
||||
import SkillTree from "./components/pages/SkillTree/SkillTree";
|
||||
import AdminEventPage from "./components/pages/AdminEventPage/AdminEventPage";
|
||||
import Teams from "./components/pages/Teams/Teams";
|
||||
import MyTeams from "./components/pages/MyTeams/MyTeams";
|
||||
|
||||
const router = createBrowserRouter([
|
||||
{
|
||||
{
|
||||
path: "*",
|
||||
element: <TemplateWeb />,
|
||||
children: [{
|
||||
path: "",
|
||||
element: <TemplateWeb />,
|
||||
children: [
|
||||
{
|
||||
path: "",
|
||||
element: <Landing />
|
||||
}
|
||||
]
|
||||
element: <Landing />,
|
||||
}]
|
||||
},
|
||||
{
|
||||
path: "dash",
|
||||
element: <General />,
|
||||
children: [{
|
||||
path: "main",
|
||||
element: <Main />,
|
||||
},
|
||||
{
|
||||
path: "*",
|
||||
element: <General />,
|
||||
children: [
|
||||
{
|
||||
path: "login",
|
||||
element: <Main />
|
||||
},
|
||||
{
|
||||
path: "successful",
|
||||
element: <Successful />
|
||||
}
|
||||
]
|
||||
path: "teams",
|
||||
element: <Teams />,
|
||||
},
|
||||
{
|
||||
path: "dash",
|
||||
element: <General />,
|
||||
children: [
|
||||
{
|
||||
path: "eventlist",
|
||||
element: <AdminEventPage />
|
||||
},
|
||||
{
|
||||
path: "admin",
|
||||
element: <AdminPage />,
|
||||
children: [
|
||||
{
|
||||
path: "*",
|
||||
element: <AdminPage />
|
||||
}],
|
||||
},
|
||||
{
|
||||
path: "skill-tree",
|
||||
element: <SkillTree />
|
||||
}
|
||||
]
|
||||
}
|
||||
])
|
||||
path: "my-teams",
|
||||
element: <MyTeams />,
|
||||
},
|
||||
]
|
||||
},
|
||||
])
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<>
|
||||
|
||||
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 19 KiB |
@@ -1,33 +0,0 @@
|
||||
import pilot from "../assets/pilot.png";
|
||||
|
||||
export const About = () => {
|
||||
return (
|
||||
<section
|
||||
id="about"
|
||||
className="container py-24 sm:py-32"
|
||||
>
|
||||
<div className="bg-muted/50 border rounded-lg py-12">
|
||||
<div className="px-6 flex flex-col-reverse md:flex-row gap-8 md:gap-12">
|
||||
<img
|
||||
src={pilot}
|
||||
alt=""
|
||||
className="w-[300px] object-contain rounded-lg"
|
||||
/>
|
||||
<div className="bg-green-0 flex flex-col justify-between">
|
||||
<div className="pb-6">
|
||||
<h2 className="text-3xl md:text-4xl font-bold">
|
||||
<span className="bg-gradient-to-b from-primary/60 to-primary text-transparent bg-clip-text">
|
||||
About{" "}
|
||||
</span>
|
||||
SkillHub
|
||||
</h2>
|
||||
<p className="text-xl text-muted-foreground mt-4">
|
||||
SkillHub is a free to use service to easily craete balanced and dedicated teams for hackatons. Our clever algorithms will help you find and create the best team for you.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
@@ -1,71 +0,0 @@
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
} from "../components/ui/accordion";
|
||||
|
||||
interface FAQProps {
|
||||
question: string;
|
||||
answer: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
const FAQList: FAQProps[] = [
|
||||
{
|
||||
question: "Is this service free?",
|
||||
answer: "Yes. It is a free to use service.",
|
||||
value: "item-1",
|
||||
},
|
||||
{
|
||||
question: "How it works?",
|
||||
answer:
|
||||
"It finds the best matches for you and requirements of event to cover all skills needed for the event.",
|
||||
value: "item-2",
|
||||
}
|
||||
];
|
||||
|
||||
export const FAQ = () => {
|
||||
return (
|
||||
<section
|
||||
id="faq"
|
||||
className="container py-24 sm:py-32"
|
||||
>
|
||||
<h2 className="text-3xl md:text-4xl font-bold mb-4">
|
||||
Frequently Asked{" "}
|
||||
<span className="bg-gradient-to-b from-primary/60 to-primary text-transparent bg-clip-text">
|
||||
Questions
|
||||
</span>
|
||||
</h2>
|
||||
|
||||
<Accordion
|
||||
type="single"
|
||||
collapsible
|
||||
className="w-full AccordionRoot"
|
||||
>
|
||||
{FAQList.map(({ question, answer, value }: FAQProps) => (
|
||||
<AccordionItem
|
||||
key={value}
|
||||
value={value}
|
||||
>
|
||||
<AccordionTrigger className="text-left">
|
||||
{question}
|
||||
</AccordionTrigger>
|
||||
|
||||
<AccordionContent>{answer}</AccordionContent>
|
||||
</AccordionItem>
|
||||
))}
|
||||
</Accordion>
|
||||
|
||||
<h3 className="font-medium mt-4">
|
||||
Still have questions?{" "}
|
||||
<a
|
||||
href="#"
|
||||
className="text-primary transition-all border-primary hover:border-b-2"
|
||||
>
|
||||
Contact us
|
||||
</a>
|
||||
</h3>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
@@ -1,99 +0,0 @@
|
||||
import { Badge } from "./ui/badge";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "../components/ui/card";
|
||||
import image from "../assets/growth.png";
|
||||
import image3 from "../assets/reflecting.png";
|
||||
import image4 from "../assets/looking-ahead.png";
|
||||
|
||||
interface FeatureProps {
|
||||
title: string;
|
||||
description: string;
|
||||
image: string;
|
||||
}
|
||||
|
||||
const features: FeatureProps[] = [
|
||||
{
|
||||
title: "Responsive Design",
|
||||
description:
|
||||
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Nisi nesciunt est nostrum omnis ab sapiente.",
|
||||
image: image4,
|
||||
},
|
||||
{
|
||||
title: "Intuitive user interface",
|
||||
description:
|
||||
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Nisi nesciunt est nostrum omnis ab sapiente.",
|
||||
image: image3,
|
||||
},
|
||||
{
|
||||
title: "AI-Powered insights",
|
||||
description:
|
||||
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Nisi nesciunt est nostrum omnis ab sapiente.",
|
||||
image: image,
|
||||
},
|
||||
];
|
||||
|
||||
const featureList: string[] = [
|
||||
"Dark/Light theme",
|
||||
"Reviews",
|
||||
"Features",
|
||||
"Pricing",
|
||||
"Contact form",
|
||||
"Our team",
|
||||
"Responsive design",
|
||||
"Newsletter",
|
||||
"Minimalist",
|
||||
];
|
||||
|
||||
export const Features = () => {
|
||||
return (
|
||||
<section
|
||||
id="features"
|
||||
className="container py-24 sm:py-32 space-y-8"
|
||||
>
|
||||
<h2 className="text-3xl lg:text-4xl font-bold md:text-center">
|
||||
Many{" "}
|
||||
<span className="bg-gradient-to-b from-primary/60 to-primary text-transparent bg-clip-text">
|
||||
Great Features
|
||||
</span>
|
||||
</h2>
|
||||
|
||||
<div className="flex flex-wrap md:justify-center gap-4">
|
||||
{featureList.map((feature: string) => (
|
||||
<div key={feature}>
|
||||
<Badge
|
||||
variant="secondary"
|
||||
className="text-sm"
|
||||
>
|
||||
{feature}
|
||||
</Badge>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||
{features.map(({ title, description, image }: FeatureProps) => (
|
||||
<Card key={title}>
|
||||
<CardHeader>
|
||||
<CardTitle>{title}</CardTitle>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent>{description}</CardContent>
|
||||
|
||||
<CardFooter>
|
||||
<img
|
||||
src={image}
|
||||
alt="About feature"
|
||||
className="w-[200px] lg:w-[300px] mx-auto"
|
||||
/>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
@@ -1,63 +0,0 @@
|
||||
import { LogoIcon } from "./Icons";
|
||||
|
||||
export const Footer = () => {
|
||||
return (
|
||||
<footer id="footer">
|
||||
<hr className="w-11/12 mx-auto" />
|
||||
|
||||
<section className="container py-20 grid grid-cols-2 md:grid-cols-4 xl:grid-cols-6 gap-x-12 gap-y-8">
|
||||
<div className="col-span-full xl:col-span-2">
|
||||
<a
|
||||
href="#"
|
||||
className="font-bold text-xl flex"
|
||||
>
|
||||
<LogoIcon />
|
||||
SkillHub
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-2">
|
||||
<h3 className="font-bold text-lg">About</h3>
|
||||
<div>
|
||||
<a
|
||||
href="#howItWorks"
|
||||
className="opacity-60 hover:opacity-100"
|
||||
>
|
||||
How it works
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<a
|
||||
href="#team"
|
||||
className="opacity-60 hover:opacity-100"
|
||||
>
|
||||
Team
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<a
|
||||
href="#faq"
|
||||
className="opacity-60 hover:opacity-100"
|
||||
>
|
||||
FAQ
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="container pb-14 text-center">
|
||||
<h3>
|
||||
© 2024{" "}
|
||||
<a
|
||||
href="#"
|
||||
className="text-primary transition-all border-primary hover:border-b-2"
|
||||
>
|
||||
Animulichki
|
||||
</a>
|
||||
</h3>
|
||||
</section>
|
||||
</footer>
|
||||
);
|
||||
};
|
||||
@@ -1,44 +0,0 @@
|
||||
import { buttonVariants } from "./ui/button";
|
||||
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
export const Hero = () => {
|
||||
return (
|
||||
<section className="container grid lg:grid-cols-2 place-items-center py-20 md:py-32 gap-10">
|
||||
<div className="text-center lg:text-start space-y-6">
|
||||
<main className="text-5xl md:text-6xl font-bold">
|
||||
<h1 className="inline">
|
||||
<span className="inline bg-gradient-to-r from-[#F596D3] to-[#D247BF] text-transparent bg-clip-text">
|
||||
SkillHub
|
||||
</span>{" "}
|
||||
</h1>{" "}
|
||||
for{" "}
|
||||
<h2 className="inline">
|
||||
<span className="inline bg-gradient-to-r from-[#61DAFB] via-[#1fc0f1] to-[#03a3d7] text-transparent bg-clip-text">
|
||||
Organizations
|
||||
</span>{" "}
|
||||
</h2>
|
||||
</main>
|
||||
|
||||
<p className="text-xl text-muted-foreground md:w-10/12 mx-auto lg:mx-0">
|
||||
Build dream teams for hackatons depends on your needs from scratch
|
||||
with SkillHub.
|
||||
</p>
|
||||
|
||||
<div className="space-y-4 md:space-y-0 md:space-x-4">
|
||||
<Link
|
||||
to={"login"}
|
||||
className={`w-full md:w-1/3 border ${buttonVariants({
|
||||
variant: "default",
|
||||
})}`}
|
||||
>
|
||||
Get started
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Shadow effect */}
|
||||
<div className="shadow"></div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
@@ -1,72 +0,0 @@
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "./ui/card";
|
||||
import { MedalIcon, MapIcon, PlaneIcon, GiftIcon } from "../components/Icons";
|
||||
|
||||
interface FeatureProps {
|
||||
icon: JSX.Element;
|
||||
title: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
const features: FeatureProps[] = [
|
||||
{
|
||||
icon: <MapIcon />,
|
||||
title: "Events",
|
||||
description:
|
||||
"Organizator creates an event where participants can join.",
|
||||
},
|
||||
{
|
||||
icon: <GiftIcon />,
|
||||
title: "Data",
|
||||
description:
|
||||
"Organizator can import users data from excel or participants can register via form.",
|
||||
},
|
||||
{
|
||||
icon: <PlaneIcon />,
|
||||
title: "Algorythm",
|
||||
description:
|
||||
"Organizator runs algorythm on users data and algrorythm creates dream teams.",
|
||||
},
|
||||
{
|
||||
icon: <MedalIcon />,
|
||||
title: "Results",
|
||||
description:
|
||||
"Organizator can view teams and it's strength and participants get email with results.",
|
||||
},
|
||||
];
|
||||
|
||||
export const HowItWorks = () => {
|
||||
return (
|
||||
<section
|
||||
id="howItWorks"
|
||||
className="container text-center py-24 sm:py-32"
|
||||
>
|
||||
<h2 className="text-3xl md:text-4xl font-bold ">
|
||||
How It{" "}
|
||||
<span className="bg-gradient-to-b from-primary/60 to-primary text-transparent bg-clip-text">
|
||||
Works{" "}
|
||||
</span>
|
||||
Step-by-Step Guide
|
||||
</h2>
|
||||
<p className="md:w-3/4 mx-auto mt-4 mb-8 text-xl text-muted-foreground">
|
||||
Our service is easy-to-use and intuitive to use.
|
||||
</p>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8">
|
||||
{features.map(({ icon, title, description }: FeatureProps) => (
|
||||
<Card
|
||||
key={title}
|
||||
className="bg-muted/50"
|
||||
>
|
||||
<CardHeader>
|
||||
<CardTitle className="grid gap-4 place-items-center">
|
||||
{icon}
|
||||
{title}
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>{description}</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
@@ -1,664 +0,0 @@
|
||||
export const LogoIcon = () => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className="lucide lucide-panels-top-left mr-2 w-6 h-6"
|
||||
>
|
||||
<rect
|
||||
width="18"
|
||||
height="18"
|
||||
x="3"
|
||||
y="3"
|
||||
rx="2"
|
||||
/>
|
||||
<path d="M3 9h18" />
|
||||
<path d="M9 21V9" />
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const MedalIcon = () => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 128 128"
|
||||
className="w-14 fill-primary"
|
||||
>
|
||||
<title>Free Icons</title>
|
||||
<g
|
||||
id="Layer_8"
|
||||
data-name="Layer 8"
|
||||
>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M60.59,60.42a2.14,2.14,0,0,1,1.89-2.06c.39-.06,1,.63,1.11.72a10,10,0,0,1,.19,1.42c0,.24-.62,5.27-1,7.2-.07.35-.15.7-.26,1.07a7.47,7.47,0,0,1-.27.78,9.1,9.1,0,0,1-.39.84,4.27,4.27,0,0,1-1.17,1.36,4.23,4.23,0,0,1-1.67.59l-1,.08-.56.06q-1.2.15-2.4.36c-.39.07-.82.15-1.17.23h0s0,0,0,0a.21.21,0,0,0-.12.07.16.16,0,0,0,0,.1.38.38,0,0,0,.07.08l0,0,.1.06.19.12c.53.33,1.08.63,1.63.91s1.12.55,1.69.79c.16.07.86.36,1.42.54a2.93,2.93,0,0,1,1.54.74c.11.11.2.22.27.3a2,2,0,0,1,.24.43,7.33,7.33,0,0,1,.31,1,8.28,8.28,0,0,1-.29,2.83l-.13.65c0,.09,0,0,0,.06s0,0,0,0,0,.08-.13.22a4.36,4.36,0,0,0-.31.53.48.48,0,0,0-.08.23c0,.1.1.12.28.1l.12,0c.07,0,.14-.14.22,0,.22.31.56,0,1-.27A28.33,28.33,0,0,1,64.33,81a7.59,7.59,0,0,1,1.44-.47c.44-.12.57.47.48.61-.25.4.19.41.36.57a.65.65,0,0,1,.15.2,26,26,0,0,1-2,2.19l-.77.8-.19.2-.23.22-.56.51c-.68.62-1.4,1.26-1.6,1.41l-.52.41c-.38.33-1,.81-2.05,1.76l-1,.89a2.29,2.29,0,0,1-.32.26l-.26.12-.57.26a3.11,3.11,0,0,1-.3.12l-.23,0-.47.09a1.41,1.41,0,0,1-.52-.15l-.1-.08c-.07,0-.2-.09-.27-.13a1.06,1.06,0,0,1-.41-.38,2.31,2.31,0,0,1-.23-.54c-.07-.17-.15-.27-.18-.35a3.44,3.44,0,0,1,.19-2.09l1.5-6.45.11-.54.06-.3c0-.08,0-.24,0-.25h0s0,0,0,0a.08.08,0,0,0,0,0s0,0,0,0h0l-.21-.09a8.47,8.47,0,0,1-1.86-1.09,3.65,3.65,0,0,0-.75-.41l-.83-.4-.41-.22-.53-.29a21.28,21.28,0,0,1-2.69-1.73,5.94,5.94,0,0,1-1.74-2,3.49,3.49,0,0,1-.31-1,3.12,3.12,0,0,1,0-.54c0-.2.14-.41.13-.59a2,2,0,0,1,.56-.91l.38-.4A1.83,1.83,0,0,1,47.9,70l.55-.35c.19-.11.44-.2.66-.3a11,11,0,0,1,1.47-.51,10.53,10.53,0,0,1,1.17-.23l1.32-.22c.83-.18,1.67-.32,2.51-.43l1.27-.15.64-.06.26,0a.36.36,0,0,0,.18,0,.29.29,0,0,0,.11-.16.64.64,0,0,0,.06-.18c.06-.2.14-.47.2-.73.15-.51,1.23-3.38,1.33-4.15C59.69,62.05,60.59,60.82,60.59,60.42Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-2"
|
||||
d="M56.23,92.36c-.24,0-.49,0-.73,0a4.27,4.27,0,0,1-.68-.18c-.22-.08-.42-.22-.63-.32a3.33,3.33,0,0,1-.48-.51A3.4,3.4,0,0,1,53.23,90c0-.25,0-.49-.07-.74v-.49a23,23,0,0,1,.39-3.43c.19-1.1.41-2.18.66-3.25l.39-1.6.08-.32,0-.07.05-.15s-.08-.06-.12-.09l-.07,0-.15-.06-1.57-.6a26.61,26.61,0,0,1-3.19-1.45,17.82,17.82,0,0,1-2.83-1.88,14.2,14.2,0,0,1-1.28-1.18L45,74c-.27-.3-.53-.73-.8-1.09a2.91,2.91,0,0,1-.34-1.23,2.5,2.5,0,0,1,1.54-1.85,9.67,9.67,0,0,1,1.91-.71,31.71,31.71,0,0,1,3.21-.68c1.07-.17,2.13-.31,3.2-.41.53-.05,1.07-.1,1.61-.13l.59,0h.29l1.88-5.28c.74-2,1.46-4,2.42-5.94l.18-.36c.08-.15.18-.3.28-.45a2.26,2.26,0,0,1,.7-.74A2.45,2.45,0,0,1,63.38,55a2.84,2.84,0,0,1,.82.4,4.36,4.36,0,0,1,.58.43,15.1,15.1,0,0,1,1.81,1.87c1.07,1.29,2,2.59,3,3.87.61.8,1.24,1.58,1.87,2.36l1,1.15c.18.21.33.38.5.55l.37-.18.87-.37c.66-.27,1.32-.52,2-.73a12.11,12.11,0,0,1,4.37-.7,1.82,1.82,0,0,1,1,.32c.19.14.24.26.18.37s-.6.33-1.17.62c-1.15.54-3,1.59-5.43,2.6l-.44.18L74,68c-.6.27-1.2.57-1.79.85L71,67.47l-.59-.71-.32-.39c-.42-.53-.84-1.05-1.24-1.58L66.5,61.61c-.79-1-1.57-2.09-2.36-3A8.65,8.65,0,0,0,63,57.48c-.12-.07-.07-.06-.08-.06l0,0a.06.06,0,0,0-.06,0s0,0,0,0l0,0-.14.26c-.19.37-.38.79-.57,1.21-.37.83-.72,1.7-1.07,2.57-.69,1.75-1.36,3.53-2,5.31L58.5,68l-.68,2a40.26,40.26,0,0,0-4.06.23c-1.09.12-2.18.28-3.25.48a23.09,23.09,0,0,0-3.13.77l-.36.13-.14.05a1.09,1.09,0,0,0-.23.14c-.07.05-.15.12-.14.21s.08.16.12.24a2.07,2.07,0,0,0,.26.33,8.43,8.43,0,0,0,.57.64,14.52,14.52,0,0,0,4.23,2.9c.8.38,1.62.72,2.48,1l1.4.53a9.43,9.43,0,0,1,1.9,1L57,80.38l-.29,1.17c-.17.69-.33,1.39-.48,2.09a38.1,38.1,0,0,0-.68,4.17,10.88,10.88,0,0,0,0,1.36,1,1,0,0,0,.19.67.71.71,0,0,0,.68.06.82.82,0,0,0,.19-.06l.28-.13c.19-.08.39-.22.59-.32a22,22,0,0,0,4.38-3.85c.72-.77,1.39-1.58,2.06-2.41l1-1.25L66.2,80l1.88,1.12,1.29.76c.86.5,1.73,1,2.6,1.45s1.74.93,2.63,1.35c.44.22.88.42,1.33.61.22.11.44.18.66.28l.33.12.22.08a3.71,3.71,0,0,0,.5.13c.15,0,.36.07.43-.12a1.71,1.71,0,0,0,.14-.94,11.65,11.65,0,0,0-.75-3.18,25.78,25.78,0,0,0-1.4-3.08c-.27-.5-.55-1-.84-1.49-.1-.18-.42-.7-.62-1.07l-.16-.3c0-.11-.15-.21,0-.31l.32-.61.32-.53.28-.43c.16-.22.32-.45.49-.67A14.46,14.46,0,0,1,76.9,72a10.48,10.48,0,0,1,3.65-2.44,3,3,0,0,1,2-.15,2.68,2.68,0,0,1,.65.25c.5.42-.94,1-3,2.56a12.58,12.58,0,0,0-2.09,2c-.31.37-.6.76-.87,1.15l-.09.15v0l0,.06a.08.08,0,0,0,0,.11l0,0s0,0,.11.17.28.48.42.72c.28.48.54,1,.79,1.49a23.31,23.31,0,0,1,1.35,3.19A15.29,15.29,0,0,1,80.33,83c.07.3.12.61.17.92l0,.49a2,2,0,0,1,0,.25V85a4.1,4.1,0,0,1-.86,2.82l-.24.27-.12.13-.17,0a3.61,3.61,0,0,1-.67.12,4.9,4.9,0,0,1-1.47-.18A13.11,13.11,0,0,1,75,87.48c-.53-.23-1.06-.47-1.57-.72-1-.5-2-1-3-1.56L68,83.85l-1.09-.63h0l-1.32,1.7c-.76,1-1.59,1.89-2.43,2.8a31.28,31.28,0,0,1-2.78,2.59,17.24,17.24,0,0,1-1.62,1.16c-.31.17-.6.35-1,.51a2.88,2.88,0,0,1-.67.25l-.83.2Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M111.88,50c0,.19-.29.15-.64,0-.11-.05-.36-.3-.36-.37a2.55,2.55,0,0,1,0-.4c0-.07.56-.89.76-1.17a3.43,3.43,0,0,1,.64-.73c.49-.43,1-.88,1.48-1.28a1.3,1.3,0,0,1,.38-.22,5.46,5.46,0,0,0,1.26-.79c.06-.05.14-.09.17-.19a4.18,4.18,0,0,1,1.37-.92c.46-.08.86-.24,1.31-.3.07,0,.12,0,.21,0a.43.43,0,0,0,.44,0,1.8,1.8,0,0,1,.58,0,2.34,2.34,0,0,1,.33.09c.1,0,.13.2.11.23s0,.15.09.22l0,.07s-.17.27-.32.57a4.25,4.25,0,0,1-.4.54c0,.05-1.21.87-1.32,1a.53.53,0,0,1-.25.08l-1,.74c-.22.1-.38.28-.67.27a.22.22,0,0,0-.14.06,10.28,10.28,0,0,1-1.07.62c-.18.11-.34.25-.51.37l-.11,0a.59.59,0,0,0-.14.06,9.53,9.53,0,0,0-1.16.94c-.08.08-.61.31-.69.42S111.89,49.93,111.88,50Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M111.62,71.77c-.19.11-.31-.14-.45-.61a1.28,1.28,0,0,1,0-.66,2.18,2.18,0,0,1,.38-.3,8.39,8.39,0,0,1,1.75-.1,3.86,3.86,0,0,1,1.18.22,21.64,21.64,0,0,1,2.21.88,1.59,1.59,0,0,1,.43.3,7.06,7.06,0,0,0,1.47,1,.43.43,0,0,0,.28.1,5.4,5.4,0,0,1,1.63,1.05,14.3,14.3,0,0,1,.91,1.29c0,.06.12.09.11.2,0,.26.12.33.22.45a4,4,0,0,1,.37.54,1.06,1.06,0,0,1,.09.37c0,.11-.18.26-.22.26s-.14.13-.2.21l-.07.08s-1.3-.32-1.41-.37l-.26-.14-.55-.28c-.43-.18-.8-.46-.9-.48s-.14-.14-.2-.23-1.23-.64-1.27-.66c-.22-.18-.5-.24-.63-.55,0-.06-.08-.08-.13-.11-.41-.21-.78-.5-1.18-.75a4.18,4.18,0,0,0-.64-.31s-.06-.06-.1-.09a.41.41,0,0,0-.13-.1,6.5,6.5,0,0,0-1.55-.54c-.12,0-.65-.37-.8-.35S111.7,71.71,111.62,71.77Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M10.08,99.67c-.1.22-.37,0-.76-.35A1.8,1.8,0,0,1,9,98.64a2.27,2.27,0,0,1,.14-.5,15.36,15.36,0,0,1,1.31-1.07,4.1,4.1,0,0,1,1-.57l2.11-.93a1.61,1.61,0,0,1,.49-.13,5,5,0,0,0,1.66-.54.45.45,0,0,0,.24-.17A6.37,6.37,0,0,1,17.68,94c.52,0,1-.14,1.53-.22.08,0,.14,0,.24,0a.55.55,0,0,0,.52,0,4.58,4.58,0,0,1,.66-.08,1.72,1.72,0,0,1,.38.08c.12,0,.16.25.14.29s.06.18.11.26l0,.09a12.06,12.06,0,0,1-1,1.23c0,.1-1.63.92-1.8,1a.68.68,0,0,1-.32.07c-.05,0-1.32.74-1.37.76-.29.1-.53.29-.88.23-.07,0-.12,0-.17,0a10.55,10.55,0,0,1-1.46.52c-.25.08-.48.21-.72.31a.59.59,0,0,1-.14,0,1,1,0,0,0-.18,0,13.45,13.45,0,0,0-1.68.76c-.12.08-.83.15-1,.25S10.13,99.58,10.08,99.67Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M14.57,70.84c.17-.07.22.17.21.6a1.54,1.54,0,0,1-.17.56,2.28,2.28,0,0,1-.31.22c-.07,0-.87,0-1.14,0a2.31,2.31,0,0,1-.75-.08c-.5-.1-1-.17-1.46-.22a.87.87,0,0,1-.31-.1,2.11,2.11,0,0,0-1.07-.18.19.19,0,0,0-.18.06,3.94,3.94,0,0,1-1.14.1,4.62,4.62,0,0,0-1-.19s-.09,0-.15,0-.23-.09-.33-.08-.27,0-.43,0a1.71,1.71,0,0,1-.27-.11A.4.4,0,0,1,6,71.18c0-.1-.07-.18-.11-.27a.15.15,0,0,1,0-.09A3.47,3.47,0,0,1,6.61,70a11.19,11.19,0,0,1,1.53-.59.6.6,0,0,1,.26,0,12.21,12.21,0,0,1,1.21-.2c.24,0,.48,0,.69.15,0,0,.09,0,.14,0a4.94,4.94,0,0,1,1.14.25,5.78,5.78,0,0,0,.57.12l.09.06.12.06c.45.08.86.28,1.31.33.1,0,.52.33.64.33S14.5,70.87,14.57,70.84Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M20.53,56.28c.23,0,.2.33,0,.74a1.37,1.37,0,0,1-.47.44,3.44,3.44,0,0,1-.43,0c-.05,0-.93-.46-1.24-.59a4.44,4.44,0,0,1-.84-.5c-.53-.39-1.09-.75-1.64-1.12a2.35,2.35,0,0,1-.33-.3,4.11,4.11,0,0,0-1.21-1A.34.34,0,0,0,14.1,54a5.51,5.51,0,0,1-1.45-.89c-.29-.37-.62-.69-.94-1,0,0-.11-.06-.12-.16s-.14-.28-.25-.37a2.7,2.7,0,0,1-.42-.41.86.86,0,0,1-.12-.34c0-.11.15-.31.19-.32s.13-.17.18-.27a.44.44,0,0,1,.06-.1,5.16,5.16,0,0,1,1.35.19l.79.38.89.42c.1,0,.15.12.22.2s1.21.62,1.25.65c.21.17.48.26.61.56a.2.2,0,0,0,.12.1,8.33,8.33,0,0,1,1.11.87c.18.15.39.27.58.41a.28.28,0,0,1,.08.11.68.68,0,0,0,.12.12c.47.32.87.73,1.37,1,.12.07.49.62.62.71S20.44,56.27,20.53,56.28Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M42.93,17.33c.84,1.48,1.7,2.93,2.63,4.35s1.95,2.78,3,4.11,2.17,2.62,3.26,3.92,2.24,2.55,3.41,3.77a1.49,1.49,0,0,1-.07,2.12,1.46,1.46,0,0,1-2.15,0c-1.2-1.3-2.33-2.65-3.41-4a50,50,0,0,1-3-4.33c-1-1.48-1.84-3-2.65-4.57A21.14,21.14,0,0,1,42,17.68.52.52,0,0,1,42.93,17.33Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M76.5,16.43A31.28,31.28,0,0,0,75,20.13c-.43,1.28-.8,2.6-1.11,3.94a53.72,53.72,0,0,0-1.31,8c-.07.73-1,1-1.93,1s-1.82-.57-1.69-1.43a51.07,51.07,0,0,1,2.44-8.34,36.5,36.5,0,0,1,1.75-3.95,11.91,11.91,0,0,1,2.53-3.62C76,15.49,76.57,16,76.5,16.43Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M94.08,19.28c-.62,1.58-1.13,3.24-1.65,4.9l-1.55,5c-.53,1.68-1.09,3.36-1.74,5a30.91,30.91,0,0,1-2.4,5,1.41,1.41,0,0,1-1.21.67,1.88,1.88,0,0,1-1.23-.51c-.69-.64-1.13-1.55-.63-2.25a29.26,29.26,0,0,0,2.49-4.23c.77-1.52,1.47-3.1,2.17-4.68l2.09-4.81c.71-1.61,1.43-3.22,2.3-4.8C93,18.2,94.2,18.81,94.08,19.28Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M29,87.07a40.44,40.44,0,0,0,26.56,23.69,35.43,35.43,0,0,0,13.33.83,40.89,40.89,0,0,0,21.52-9.54,37,37,0,0,0,12.34-20,41.17,41.17,0,0,0-.92-21.11A37.28,37.28,0,0,0,95.55,49,38.86,38.86,0,0,0,85.44,40c-2.37-1.52-1.76-2,.76-1.41a22.48,22.48,0,0,1,2.22.7c.82.35,1.7.84,2.67,1.38.47.29,1,.56,1.47.91s1,.75,1.46,1.16,1,.84,1.5,1.29.93,1,1.4,1.54a39.09,39.09,0,0,1,7.45,13,43.54,43.54,0,0,1,2.34,14.69A42.32,42.32,0,0,1,104,87.9a39,39,0,0,1-8,12.59A46.37,46.37,0,0,1,81.47,111a41.07,41.07,0,0,1-17.73,3.82,40.69,40.69,0,0,1-9.88-1.53,45,45,0,0,1-9.15-4,46.74,46.74,0,0,1-8-6,45.07,45.07,0,0,1-6.41-7.58,41.72,41.72,0,0,1-5.2-11,39.15,39.15,0,0,1-1.61-12.07,38.61,38.61,0,0,1,1.29-9.14,45.16,45.16,0,0,1,1.43-4.4L27.18,57c.3-.71.7-1.37,1-2.06a43.35,43.35,0,0,1,5.19-7.59,46.45,46.45,0,0,1,6.66-6.27,44.21,44.21,0,0,1,12.36-6.72A40,40,0,0,1,66.29,32l1.55,0,1.55.12c.52,0,1,.06,1.55.14l1.56.25a23.18,23.18,0,0,1,2.63.56,16.3,16.3,0,0,1,2.15.63l1.74.63a14.7,14.7,0,0,1,1.36.64,7.77,7.77,0,0,1,3,2.23,6.31,6.31,0,0,1,.7,1c.18.43-.48.4-1.78,0-.32-.1-.68-.23-1.08-.38l-1.35-.43-1.57-.53-1.82-.51a38.48,38.48,0,0,0-23.67,1A41.11,41.11,0,0,0,42,43.19a42.83,42.83,0,0,0-4.65,4.08,42,42,0,0,0-4,4.76,38.52,38.52,0,0,0-4.4,8A37,37,0,0,0,26.76,69a35.34,35.34,0,0,0,0,9.19A34.61,34.61,0,0,0,29.09,87Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M26.51,20.08c1.09,1.75,2.31,3.42,3.51,5.1s2.5,3.3,3.74,4.94c2.53,3.26,5.16,6.44,7.91,9.46C43.2,41.33,40,44.21,38.4,42.3c-2.56-3.39-4.9-6.89-7.12-10.47-1.12-1.78-2.13-3.63-3.13-5.48s-1.91-3.75-2.78-5.67C25.15,20.13,26.15,19.61,26.51,20.08Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M31.36,32c1.58,1.73,3.19,3.43,4.87,5,.84.78,1.72,1.51,2.63,2.29s1.78,1.63,2.62,2.48c.93,1-1.07,2.7-1.91,1.7s-1.46-1.76-2.24-2.6-1.62-1.7-2.4-2.61-1.49-1.88-2.19-2.84-1.34-2-2-2.93C30.58,32.14,31.11,31.73,31.36,32Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M76.29,16.69c-.08.18-.3.16-.63,0-.1,0-.31-.25-.3-.32a2.34,2.34,0,0,1,.11-.4,6,6,0,0,1,1.22-1.18,3.85,3.85,0,0,1,1-.58,9.73,9.73,0,0,1,2.34-.56,1.51,1.51,0,0,1,.52,0c.6.06,1.19.06,1.77.08a.7.7,0,0,0,.29,0,6,6,0,0,1,1.92.23l1.4.59c.07,0,.15,0,.19.11s.26.19.4.25a3.38,3.38,0,0,1,.58.27,1.34,1.34,0,0,1,.25.23c.07.07,0,.22-.07.23s-.06.13-.07.2,0,.05,0,.07S86,16,85.87,16L85,15.81a9.1,9.1,0,0,0-1-.1.9.9,0,0,1-.28-.08,13.5,13.5,0,0,0-1.42-.07,3.16,3.16,0,0,1-.8-.12.29.29,0,0,0-.16,0c-.46,0-.91,0-1.37,0a5.09,5.09,0,0,0-.68.12h-.13a.44.44,0,0,0-.16,0,4.94,4.94,0,0,0-1.49.59,4.59,4.59,0,0,0-.78.37C76.65,16.59,76.32,16.6,76.29,16.69Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M43,18c.17.1.14.32,0,.56a.6.6,0,0,1-.34.18,1.79,1.79,0,0,1-.3-.09,2.92,2.92,0,0,0-.89-.53c-.21-.09-.44-.14-.65-.23a5.75,5.75,0,0,0-1.52-.2,1.1,1.1,0,0,1-.36,0,3.25,3.25,0,0,0-1.28,0,.39.39,0,0,0-.21.06A7.17,7.17,0,0,1,36,18l-1.21,0c-.06,0-.12,0-.18,0a.53.53,0,0,0-.38-.06,4.68,4.68,0,0,1-.53,0,1.43,1.43,0,0,1-.27-.09c-.08,0-.06-.17,0-.19s0-.12,0-.17a.15.15,0,0,1,0-.06,4.07,4.07,0,0,1,.46-.29,4.51,4.51,0,0,1,.54-.3l.22-.08c.14-.06.32-.11.5-.17l.84-.25a.82.82,0,0,1,.27,0S37.35,16,37.41,16a1.58,1.58,0,0,1,.75,0,.38.38,0,0,0,.15,0,4.21,4.21,0,0,1,1.32.07c.23,0,.46,0,.69.09l.12.05.16.05a5.8,5.8,0,0,1,1.58.65,2.38,2.38,0,0,1,.35.31,3.21,3.21,0,0,0,.3.37C42.91,17.64,43,18,43,18Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M34.79,84.84a34,34,0,0,0,22.3,19.88,29.73,29.73,0,0,0,11.19.7,34.34,34.34,0,0,0,18.06-8A31,31,0,0,0,96.69,80.57a34.53,34.53,0,0,0-.77-17.71,31.26,31.26,0,0,0-5.29-10,32.53,32.53,0,0,0-8.49-7.49c-2-1.27-1.48-1.68.62-1.15.53.14,1.15.34,1.86.59S86,45.52,86.85,46c.39.24.83.47,1.23.77l1.22,1q.61.51,1.26,1.08c.4.4.78.84,1.17,1.29a34.61,34.61,0,0,1,8.2,23.16A35.35,35.35,0,0,1,97.66,85.5,32.69,32.69,0,0,1,91,96.06a39,39,0,0,1-12.22,8.77A34.29,34.29,0,0,1,63.94,108a34.18,34.18,0,0,1-8.29-1.28A38.29,38.29,0,0,1,48,103.44a39.7,39.7,0,0,1-6.66-5A38.34,38.34,0,0,1,36,92.09a33.46,33.46,0,0,1-5.71-19.36,32,32,0,0,1,1.09-7.66,31.37,31.37,0,0,1,2.83-7.19,36,36,0,0,1,4.35-6.36,38.55,38.55,0,0,1,5.58-5.26,37.52,37.52,0,0,1,10.36-5.63,33.44,33.44,0,0,1,11.62-2h1.3l1.3.1a21,21,0,0,1,2.6.32,23.58,23.58,0,0,1,6.61,2.07A6.6,6.6,0,0,1,80.38,43a6.13,6.13,0,0,1,.6.8c.15.35-.4.33-1.49,0-.54-.18-1.21-.43-2-.68l-1.32-.45-1.52-.43a32.4,32.4,0,0,0-19.88.84,34.42,34.42,0,0,0-9,4.94,33,33,0,0,0-7.22,7.41,31.72,31.72,0,0,0-3.7,6.76,31.09,31.09,0,0,0-1.9,7.46,30.23,30.23,0,0,0,2,15.17Z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const MapIcon = () => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 128 128"
|
||||
className="w-14 fill-primary"
|
||||
>
|
||||
<title>Free Icons</title>
|
||||
<g
|
||||
id="Layer_45"
|
||||
data-name="Layer 45"
|
||||
>
|
||||
<polygon
|
||||
className="cls-1"
|
||||
points="11.43 77.06 7.94 77.58 38.75 118.18 116.65 109.76 118.12 106.39 40.63 113.44 11.43 77.06"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M67.52,47.87a6,6,0,0,1-6,5.77,5.68,5.68,0,1,1,6-5.77Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M38.25,39.06a20.73,20.73,0,0,0-.65,6.57,25.84,25.84,0,0,0,1.32,6.54,21.35,21.35,0,0,0,.88,2.3c.3.76.68,1.49,1,2.23A68.07,68.07,0,0,0,50.82,71c1.71,2,3.52,3.85,5.34,5.69,2.33,2.38,4.76,4.68,6.89,7.27.66.8.5.76-.22.24a36.43,36.43,0,0,1-3.47-2.78Q55.63,78,52.11,74.24a85.26,85.26,0,0,1-6.63-7.9A59,59,0,0,1,38.9,55.5a27,27,0,0,1-2.42-13.75,22.48,22.48,0,0,1,2.65-8.22,31,31,0,0,1,3.8-5.32,24.3,24.3,0,0,1,5-4.12,29.55,29.55,0,0,1,9.23-3.72c.72-.18,1.43-.29,2.15-.42s1.25-.16,1.72-.19.87,0,1.18,0a4.27,4.27,0,0,1,1.3.24,3.54,3.54,0,0,1,.39.13c.26.17-.84.3-2.76.69-5.69.78-11.62,2.86-16.06,6.92A24.21,24.21,0,0,0,40.94,33a20.72,20.72,0,0,0-2.65,6.11Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M58.48,80.3S51.27,83,54.22,84.46s9.54.47,9.54.47Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M72.46,78.55c.19-.3,3.78-.27,5.2.49s.14,2-.89,2.6A24.56,24.56,0,0,1,69,84Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M25.89,71.12c1.89-.12,3.79-.26,5.68-.43l2.06-.23c2.44-.2,4.87-.39,7.31-.62,1.08-.11,2.16-.26,3.22-.41l2.06-.3a12.51,12.51,0,0,1,2.12,0c.45.05.4.36.07.76a3.85,3.85,0,0,1-1.68,1.18c-1.38.28-2.78.5-4.18.69s-2.83.24-4.26.29c-1.71,0-3.46.37-5.19.55-1.91.19-3.83.35-5.74.52l-3.53.28c-1.79.15-3.58.24-5.35.41-1.38.12-2.72.4-4.1.5-.3,0-.59.08-.9.09-1.14,0-1.5-.12-1.75-.64-.05-.12-.12-.24-.16-.36-.1-.4.35-.75,1.16-.91a57.2,57.2,0,0,1,7.45-.95l5.7-.47Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M107.68,108q-14.42,1.6-28.85,3c-3.51.36-7,.77-10.52,1.1-6.2.55-12.39,1.08-18.61,1.48-1.55.1-3.11.19-4.67.25-.79,0-1.57.06-2.36.06-.4,0-.8,0-1.21,0l-.34,0-.45,0a2.23,2.23,0,0,1-.45-.08l-.31-.33-1.61-1.9-1.49-1.79-3-3.61L23.42,93.35c-4.44-5.46-8.9-10.93-13-16.68-1.26-1.82-.77-1.78.64-.53a62.09,62.09,0,0,1,6.44,6.77L31.07,99.64,37.89,108l3.29,3.93s.06,0,.1,0h.49c.42,0,.86,0,1.3,0,.89,0,1.78,0,2.68-.07,8.6-.4,17.56-1.47,26.36-2.33q14.52-1.45,29-3.06l8.92-1,8.12-1,.3,0,.15,0s.06,0,.06,0l0-.06-.35-.47-14.6-19.39-6.29-8.33Q95.86,74.14,94.34,72c-.52-.7-1-1.42-1.51-2.14-.24-.34-.51-.77-.7-1.06l-.14-.2a1.15,1.15,0,0,0-.26,0l-.41,0h-.55l-1.11,0-2.26.08c-5.69.16-7.55-.06-8.76-.63a6.11,6.11,0,0,1-.8-.38c-.52-.41,1.77-.7,5.92-1,1.54-.09,3.09-.23,4.66-.29.79,0,1.59-.07,2.41-.08h1a3.2,3.2,0,0,1,.51.06,6.24,6.24,0,0,1,1,.23,6.4,6.4,0,0,1,.64.86l.7,1,.67,1,1.38,1.92,2.83,3.87c3.83,5.16,7.77,10.37,11.72,15.59l10,13.24.13,1,.06.51-.56-.23h0v.06l0,.08-.06.17-.13.43c0,.19-.19.32-.41.41-.54.1-1.12.17-1.68.24l-3.93.5-6.94.82Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M77.22,24.79C70.1,19.88,60.43,19.37,52.14,22a24.46,24.46,0,0,0-8.25,4.57,20.89,20.89,0,0,0-2.89,3l-1.26,1.69c-.39.58-.73,1.19-1.1,1.79a20.39,20.39,0,0,0-2.57,7.87c-.61,5.57,1.28,11.21,4.11,16.18a68.61,68.61,0,0,0,9.29,12.25c2.24,2.41,4.56,4.76,6.9,7.11a90.56,90.56,0,0,1,6.76,7.34c1.26,1.68.93,1.55-.42.43C62,83.65,61,82.88,59.84,82c-.6-.46-1.26-.94-1.93-1.5s-1.35-1.16-2-1.81c-2.46-2.32-5-4.6-7.31-7.11a88.41,88.41,0,0,1-6.66-7.87,50.68,50.68,0,0,1-5.41-8.93A27.84,27.84,0,0,1,33.8,44.48a12.33,12.33,0,0,1,0-1.61c0-.54,0-1.09.06-1.63A25.42,25.42,0,0,1,34.36,38a23.19,23.19,0,0,1,1-3.14c.18-.51.44-1,.66-1.49a12.63,12.63,0,0,1,.74-1.47,26.2,26.2,0,0,1,1.76-2.75c.33-.44.64-.88,1-1.31s.71-.85,1.08-1.25a24,24,0,0,1,5.09-4.12A31.44,31.44,0,0,1,59.1,18.31a35.46,35.46,0,0,1,7.06.09A30.17,30.17,0,0,1,73,20.06,25.09,25.09,0,0,1,86.12,31.17a25,25,0,0,1,2.93,12.75,37,37,0,0,1-2.82,12.66c-2.55,6.24-6.44,11.56-10,17-.79,1.19-1.54,2.37-2.3,3.58S72.63,79.18,72.16,80s-1,1.37-1.28,1.89a14.89,14.89,0,0,1-1.57,2,8,8,0,0,1-.57.58c-.24.18-.2-.26.06-1.22a14.86,14.86,0,0,1,.59-1.82,25,25,0,0,1,1-2.47c2.75-5.26,6.36-10.13,9.49-15.21a56.37,56.37,0,0,0,4.16-7.86,36.86,36.86,0,0,0,2.39-8.49A24.86,24.86,0,0,0,85.2,34.67a21.31,21.31,0,0,0-8-9.83Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M58.44,43.55a5.91,5.91,0,0,0-2,4.8,5.85,5.85,0,0,0,6.34,5.29,6.15,6.15,0,0,0,3-1.12,7.92,7.92,0,0,0,2.43-3.26c.19-.38.66-.26,1,.27a2.38,2.38,0,0,1,.3,1.09A2.78,2.78,0,0,1,69.13,52a8,8,0,0,1-9.79,2.82A8.07,8.07,0,0,1,55,50.14a7.51,7.51,0,0,1,1.18-6.78,8,8,0,0,1,3.32-2.64,7.77,7.77,0,0,1,3.16-.61,7.34,7.34,0,0,1,3.1.79,8.06,8.06,0,0,1,3.57,3.39,7.29,7.29,0,0,1,.45,1c.39,1.36.18,1.85-.29,2.12a1.24,1.24,0,0,1-.34.18c-.39.11-.66-.39-.9-1.14A6.38,6.38,0,0,0,63.3,42a5.93,5.93,0,0,0-4.83,1.56Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M97.16,94.19l-2.35.18c-.29,0-.56.09-.85.11-1,.08-2,.17-3,.3a11.67,11.67,0,0,0-1.31.26,9,9,0,0,1-1.65.31c-.16,0-.24-.2-.17-.47a1.12,1.12,0,0,1,.62-.73,13.67,13.67,0,0,1,3.47-.73c.71,0,1.41-.27,2.13-.39s1.57-.25,2.36-.34l1.46-.17c.74-.09,1.49-.15,2.22-.27.57-.08,1.11-.27,1.69-.39.12,0,.25-.07.37-.08.49-.06.66.06.76.51,0,.1,0,.2.07.31a.7.7,0,0,1-.46.76,13.64,13.64,0,0,1-3,.61l-2.34.26Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M23.49,79.2l1.28,0c.16,0,.31,0,.47,0l1.66,0c.24,0,.49,0,.73,0a2.53,2.53,0,0,1,.95,0c.19.05-.06.73-.39.8a7.46,7.46,0,0,1-1.84.15,6.3,6.3,0,0,0-1.14.12l-1.27.14-.79.07c-.4,0-.8.07-1.19.13s-.6.15-.91.22l-.2,0c-.26,0-.34,0-.41-.32a1.21,1.21,0,0,1-.05-.18.44.44,0,0,1,.23-.48,5.46,5.46,0,0,1,1.6-.46c.42-.06.84-.1,1.27-.14Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M99.51,98.12l-1,0c-.12,0-.24.06-.37.06-.44,0-.88,0-1.32.06a2.68,2.68,0,0,0-.56.13,1.41,1.41,0,0,1-.73.14c-.17,0-.22-1.14.06-1.22a4.51,4.51,0,0,1,1.56-.14,4.29,4.29,0,0,0,.94-.1l1-.09.64-.06a7.48,7.48,0,0,0,1-.13c.24-.07.46-.17.69-.26l.15-.06c.19,0,.28,0,.37.28L102,97a.47.47,0,0,1-.11.5,2.55,2.55,0,0,1-1.3.55c-.34.07-.69.1-1,.14Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-2"
|
||||
d="M89.73,10.41A1.6,1.6,0,0,1,92,10.18C94.83,12.94,86.29,14,89.73,10.41Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M97.65,22.68a1.63,1.63,0,0,1,2.25-.23C102.75,25.21,94.21,26.25,97.65,22.68Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M23.93,41.47a1.22,1.22,0,0,0-1.7-.18C20.07,43.38,26.54,44.16,23.93,41.47Z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const PlaneIcon = () => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 128 128"
|
||||
className="w-14 fill-primary"
|
||||
>
|
||||
<title>Free Icons</title>
|
||||
<g
|
||||
id="Layer_4"
|
||||
data-name="Layer 4"
|
||||
>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M105.07,53.84a47.29,47.29,0,0,0-8.45-18.41A40.76,40.76,0,0,0,81,22.72a37,37,0,0,0-7-2.39,43.32,43.32,0,0,0-7.36-1.12,46.56,46.56,0,0,0-25.42,5.71,44.94,44.94,0,0,0-18.6,18.35,49.34,49.34,0,0,0-5.07,22.81,45.6,45.6,0,0,0,2.78,14.69A42.47,42.47,0,0,0,27.8,93.6c2,2.34,1.29,2.59-1.07,1.05a12.21,12.21,0,0,1-2-1.56L23.61,92l-.6-.61-.56-.68a24.69,24.69,0,0,1-2.3-3.17c-.36-.6-.72-1.22-1.09-1.87s-.63-1.35-.94-2.06a46.46,46.46,0,0,1-2.49-7.79c-.25-1.34-.53-2.68-.69-4s-.35-2.7-.35-4.06a53.42,53.42,0,0,1,1.79-16.12A55.57,55.57,0,0,1,19.14,44a38.57,38.57,0,0,1,4.14-7.08A47.1,47.1,0,0,1,35,25.63a54.07,54.07,0,0,1,17.93-8,46.7,46.7,0,0,1,19.83-.39,42.09,42.09,0,0,1,19.46,9.51,47.38,47.38,0,0,1,12.65,17.52,51.57,51.57,0,0,1,3.6,12.83,48.6,48.6,0,0,1-6.66,32.25A46.48,46.48,0,0,1,88,103.83c-8.66,5.85-19.15,8.19-29.39,7.74-1.14-.06-2.25-.15-3.38-.23s-2.23-.25-3.36-.44a44.2,44.2,0,0,1-8.68-2.22,20.76,20.76,0,0,1-2.18-1,7.78,7.78,0,0,1-1.33-1,7.39,7.39,0,0,1-.93-.89c-.27-.4.44-.42,1.9-.1l6.63,1.58c8.61,1.88,17.87,2.27,26.62-.09A41.86,41.86,0,0,0,96.27,92.53,46.74,46.74,0,0,0,105,74.22a45.83,45.83,0,0,0,0-20.35Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M41.22,94.81c-3.73,3.74-7.49,7.47-11.4,11.07-1.43,1.32-2.83,2.66-4.33,3.91a48,48,0,0,1-8.55,6,11.13,11.13,0,0,1-5.34,1.44,5.79,5.79,0,0,1-2.89-.78,4.08,4.08,0,0,1-1.83-2.56,10.32,10.32,0,0,1,.3-4.91,29.17,29.17,0,0,1,1.6-4.37,32.88,32.88,0,0,1,6.48-9.82c.94-.85,1.21-.25,1,.87a14.16,14.16,0,0,1-2.08,4.63,46.07,46.07,0,0,0-2.83,4.9,25.29,25.29,0,0,0-2,5.12c-.41,1.69-.38,3.44.41,4a3.14,3.14,0,0,0,1.91.61,6.52,6.52,0,0,0,2.44-.36,21.78,21.78,0,0,0,5.94-3.37c1.91-1.41,3.74-3,5.54-4.57,3.94-3.49,7.73-7.21,11.49-11l6.9-7c3.48-3.54,7-7.06,10.58-10.48a86.86,86.86,0,0,1,8.61-7.61,21.91,21.91,0,0,1,2.17-1.42c2.91-1.6,4.56-1.28,5.12-.53a1.71,1.71,0,0,1,.33.54c0,.28-.25.4-.7.52a12.94,12.94,0,0,0-2.06.72,20.6,20.6,0,0,0-4,2.56c-1.33,1-2.62,2.12-3.91,3.28C57.53,78.52,55,81,52.47,83.49,48.73,87.22,45,91,41.27,94.85Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M66.45,58.67l.43.51.35.37.48.48a5,5,0,0,1-.06,1c-.06.16-.13.33-.2.49l-.3.45a9.68,9.68,0,0,1-.93,1,1.64,1.64,0,0,0-.24.23c-.06,0,0,.11,0,.13a.29.29,0,0,0,.19.05,1.62,1.62,0,0,0,.44,0,2.63,2.63,0,0,0,.47-.06,9.36,9.36,0,0,0,2-.62,26.63,26.63,0,0,0,3.82-2.13c1.51-1,3-2.13,4.37-3.27,2.52-2,4.93-4.17,7.26-6.42A59.51,59.51,0,0,0,91,43.72a3,3,0,0,0,.45-3.44c-.47-1-2-.55-3.17,0a26.41,26.41,0,0,0-4.51,2.94c-1.44,1.11-2.84,2.28-4.24,3.45-1.72,1.5-.78-1.71,2.63-4.43A31.22,31.22,0,0,1,87,39a8.43,8.43,0,0,1,3.11-1,3,3,0,0,1,2,.63,3.5,3.5,0,0,1,1.07,1.7,4.55,4.55,0,0,1-.49,3.51A17.11,17.11,0,0,1,91,46.32C89.7,47.79,88.37,49.16,87,50.5a118,118,0,0,1-10.44,9.31,42.12,42.12,0,0,1-5.29,3.5,15.59,15.59,0,0,1-3,1.29,7.57,7.57,0,0,1-1.68.32,1.78,1.78,0,0,1-.46,0,3.07,3.07,0,0,1-.57-.06,5.6,5.6,0,0,1-1.07-.44,1.22,1.22,0,0,1-.54-.75,1.36,1.36,0,0,1,.27-.89,4.65,4.65,0,0,1,.69-.78l.53-.51A4.42,4.42,0,0,0,66,61c.07-.11.17-.28.07-.39l-.25-.27-.44-.51a9.77,9.77,0,0,1-.8-1.11,4.45,4.45,0,0,1-.6-1.39,1.72,1.72,0,0,1,.51-1.7,2.93,2.93,0,0,1,.84-.18,4.43,4.43,0,0,1,.72,0,8.68,8.68,0,0,1,1.26.17c.31.07.61.15.92.24l.4.12.23.09c.08.06.12-.07.18-.1l.21-.2.64-.64,2.07-2-1-.49-1.56-.83a34.89,34.89,0,0,1-3-1.85A11,11,0,0,1,64.7,48.5a2.88,2.88,0,0,1-.71-1,1.31,1.31,0,0,1,.26-1.35,4.54,4.54,0,0,1,3.56-1.38,26.23,26.23,0,0,1,3.48.27c.8.1,1.58.2,2.38.32,3,.45,3.86.68,4.43,1.2a3.41,3.41,0,0,1,.38.35c.24.37-1,.47-3.19.23-1.8-.2-3.62-.46-5.41-.65a15.37,15.37,0,0,0-2.6-.08,3.6,3.6,0,0,0-1.06.23,2.06,2.06,0,0,0-.41.23l-.19.14-.08.09h0s0,0,0,0l0,0,.11.14a2.93,2.93,0,0,0,.3.32,12.23,12.23,0,0,0,1.64,1.27A43.21,43.21,0,0,0,71.46,51l1.34.67,1.83.86L70,57.19l-.42.42c-.15.13-.27.35-.47.2L68,57.43A10.19,10.19,0,0,0,67,57.15a6.4,6.4,0,0,0-1-.15h-.39s0,0,0,0v0s0,.16.1.26a6.78,6.78,0,0,0,.86,1.33Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M84.3,62.51a9.65,9.65,0,0,0,.33-1.87c.07-.67.1-1.36.12-2,0-.5,0-1,0-1.51,0-.87,0-1.83-.08-2.61a4,4,0,0,0,0-.57,1.91,1.91,0,0,0-.06-.33s-.06-.12-.11-.11a.43.43,0,0,0-.09.1c-.1.13-.2.3-.31.46a2.09,2.09,0,0,1-.18.27,5,5,0,0,1-.43.5,4.36,4.36,0,0,1-.64.58,7.36,7.36,0,0,1-.63.47,6.23,6.23,0,0,1-1.39.76c-.14,0-.32,0-.29-.17a.21.21,0,0,1-.11-.22,1.17,1.17,0,0,1,0-.32,1.8,1.8,0,0,1,.73-1.31,13.23,13.23,0,0,0,1.12-.82,3.19,3.19,0,0,0,.43-.46c.29-.35.59-.85.87-1.27A2.75,2.75,0,0,1,84,51.5a1.51,1.51,0,0,1,.37-.15c.22,0,.38-.23.71,0a1,1,0,0,1,.57.6,5.23,5.23,0,0,1,.29,1.25c.15,1.29.14,1.7.2,2.41s.09,1.31.09,2A29,29,0,0,1,85.94,62a5.07,5.07,0,0,1-.41,1.42,1.55,1.55,0,0,1-1.47,1,2.16,2.16,0,0,1-1.16-.58,6,6,0,0,1-.73-.8,15.35,15.35,0,0,1-1.1-1.74,18.4,18.4,0,0,1-1.35-2.83,5,5,0,0,1-.21-.69c-.21-.89.06-1.47.55-1.48a.52.52,0,0,1,.29.07c.2.29.38.28.48.73A18.32,18.32,0,0,0,83,61.63a6.82,6.82,0,0,0,.55.72,3.47,3.47,0,0,0,.48.44l0,0s.09-.09.16-.31Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M68.92,62.36a3.19,3.19,0,0,1-.73.66,2.27,2.27,0,0,1-.6.26,4,4,0,0,1-1.26.1c-.28,0-.67-.41-.5-.7l.86-1.36.07-.09,0-.08a2.14,2.14,0,0,0,.13-.22.31.31,0,0,0-.2-.48s-.06,0-.09-.05l-.05,0-.19-.13c-.26-.18-.53-.36-.81-.57a4.58,4.58,0,0,1-.47-.39,3.11,3.11,0,0,1-.29-.31,2,2,0,0,1-.19-.27,1.07,1.07,0,0,1-.12-.19c0-.12-.1-.24-.14-.36l0-.18a2.15,2.15,0,0,1,0-.45,2.06,2.06,0,0,1,.29-1,2.09,2.09,0,0,1,.86-.8,2.05,2.05,0,0,1,.49-.18l.23,0h.1a2.46,2.46,0,0,1,.54,0,2.36,2.36,0,0,1,.38.08,1,1,0,0,1,.39.13,5.88,5.88,0,0,0,1.15.45l.26.07.07,0,0,0,0,0,.74-.7c.54-.54,1.07-1.11,1.56-1.69l.69-.86s0,0,0,0v0h0l-.31-.14-.51-.21-.5-.2-.54-.25-.92-.46a21.42,21.42,0,0,1-2-1.14A5.35,5.35,0,0,1,66,49.45a4,4,0,0,1-.34-.5,1.87,1.87,0,0,1-.14-.27,2.32,2.32,0,0,1-.13-.37,1.74,1.74,0,0,1-.09-.51,3,3,0,0,1,0-.6,2.53,2.53,0,0,1,1.1-1.66,3,3,0,0,1,.79-.37,5.15,5.15,0,0,1,1.52-.2c.4,0,.76,0,1.11.06.7.06,1.37.14,2,.22a4.12,4.12,0,0,0,1.31.06,31,31,0,0,1,5.26.67h.05a1.29,1.29,0,0,0,.31-.13,7.07,7.07,0,0,0,.63-.41c.33-.22.81-.62,1.24-1l1.35-1.06a33.32,33.32,0,0,1,2.87-2,2.55,2.55,0,0,1,.91-.47A8,8,0,0,0,88,40.11a6.14,6.14,0,0,1,3.35-.55,2.76,2.76,0,0,1,1.58.91c.37.37-.17.62-.31.61-.45-.06-.25.32-.34.5a.86.86,0,0,1-.11.19.42.42,0,0,1-.19,0l-.18,0-.25,0a3.31,3.31,0,0,0-1.33.4,17.94,17.94,0,0,0-2.25,1.61s-.41.3-1,.74-1.3,1.08-2,1.77-1.47,1.44-2.09,2.08a10,10,0,0,1-1.76,1.44,4.36,4.36,0,0,1-2.3.63,4.09,4.09,0,0,1-1.11-.07c-.37-.06-1.79-.27-3.19-.42s-2.72-.26-2.83-.26c-.62,0-1.24,0-1.82,0H69a1.42,1.42,0,0,1-.31,0l-.09,0v0s0,.06,0-.1a4.61,4.61,0,0,0-.16-.64c0-.15-.09-.29-.13-.43a2.57,2.57,0,0,0-.16-.37.76.76,0,0,0-.15-.26c-.07-.08-.06-.11-.12-.15s-.08,0,0,0a.45.45,0,0,0,.19-.06l0,0h0l.52-.29h0l.09-.05a4.16,4.16,0,0,0,.79-.7s0,0,.09,0l.44.25c.37.19.83.39,1.35.6l.87.4.71.34.83.42.48.25c.24.13.45.27.68.41a5.26,5.26,0,0,1,2,2.15,3.19,3.19,0,0,1,.25,1.42,1.9,1.9,0,0,1-.14.7,3.33,3.33,0,0,1-.28.69,3.72,3.72,0,0,1-.65.91,6.17,6.17,0,0,1-.48.54l-.4.43A25.27,25.27,0,0,1,72,58.9l-.47.33c-.06.06-.22.13-.34.22l-.38.24A6.38,6.38,0,0,1,70,60a2.6,2.6,0,0,1-.88,0c-1.39-.22-1.86-.55-2.55-.64l-.22,0s-.08,0-.11,0l0,0h0l.07-.28a3.68,3.68,0,0,0,.18-1.5s0,0,0,0a.23.23,0,0,0,.1,0l.35-.18a4,4,0,0,0,.48-.35l.3-.24c.08-.08.22-.22.18-.17l0,0,.1.12c.17.18.44.41.71.65l.22.2a2.83,2.83,0,0,1,.3.3c.21.19.37.39.53.56a4.44,4.44,0,0,1,.39.65,2.84,2.84,0,0,1,.21.46A2.08,2.08,0,0,1,70,61.16,7,7,0,0,1,68.92,62.36Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M44.26,15.62a9.29,9.29,0,0,1,7.24-3c1.14.06,2.54-1.62.87-1.7a13,13,0,0,0-10.15,4c-1.08,1.07,1.3,1.39,2,.66Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M111.67,47.16a8.2,8.2,0,0,1,2.38,8.72c-.41,1.09,1.62,1.07,1.93.23a9.12,9.12,0,0,0-2.46-9.84c-.66-.63-2.57.21-1.85.89Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M116.62,43.57a5.66,5.66,0,0,1,2.79,5.3c0,.89,2,.51,2-.23a6.49,6.49,0,0,0-3.22-6.11c-.61-.39-2.46.47-1.61,1Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M41.44,40.62c.2,2.67-4.89,2.84-4.43-.3.31-2.2,3.72-2.34,4.34-.18A2.23,2.23,0,0,1,41.44,40.62Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M31.38,50.19c.12,1.59-2.93,1.7-2.66-.19a1.35,1.35,0,0,1,2.6-.1A1.5,1.5,0,0,1,31.38,50.19Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M80.78,98.68c.12,1.6-2.94,1.7-2.66-.19a1.35,1.35,0,0,1,2.6-.1A1.67,1.67,0,0,1,80.78,98.68Z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const GiftIcon = () => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 128 128"
|
||||
className="w-14 fill-primary"
|
||||
>
|
||||
<title>Free Icons</title>
|
||||
<g
|
||||
id="Layer_14"
|
||||
data-name="Layer 14"
|
||||
>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M16,103.87l-.26-5.22c0-.64-.14-1.27-.17-1.91-.11-2.24-.22-4.49-.37-6.74-.08-1-.19-2-.3-3a20.29,20.29,0,0,1-.28-3.82c0-.4.4-.38.81-.08a2.58,2.58,0,0,1,1,1.58c.21,1.28.42,2.55.58,3.84s.26,2.58.31,3.89c.05,1.57.38,3.17.57,4.77s.36,3.5.5,5.26l.25,3.26c.14,1.64.21,3.29.37,4.92.12,1.27.4,2.51.58,3.77a7.83,7.83,0,0,1,.1.83c0,1.05-.16,1.39-.87,1.61a4.42,4.42,0,0,1-.48.15c-.54.1-1-.32-1.21-1.06a33.15,33.15,0,0,1-.88-6.82c-.11-1.74-.21-3.49-.32-5.24Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M37.18,115.42c3.31.12,6.62.25,9.92.31h3.62c4.26.09,8.52.17,12.77.08,1.88,0,3.77-.14,5.63-.28,1.2-.09,2.39-.22,3.57-.35s2.39-.24,3.44-.47c.65-.12.81.24.33.85a3.91,3.91,0,0,1-.5.5,6.21,6.21,0,0,1-2.57,1.09c-2.49.43-5,.69-7.44.87s-5,.13-7.46.07c-3-.08-6.07.11-9.11.13-3.35,0-6.7,0-10-.07L33.17,118c-3.12-.07-6.24-.18-9.34-.22-2.41,0-4.78.08-7.18,0-.53,0-1-.05-1.58-.12-2-.24-2.58-.54-2.92-1.17a2.43,2.43,0,0,1-.22-.42c-.12-.45.72-.69,2.13-.76,4.21-.36,8.62-.18,13.11-.14l10,.21Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M82.85,88.56l.07,6.2c0,.75.1,1.5.11,2.26,0,2.66.06,5.32.14,8,0,1.18.14,2.36.26,3.52a30.63,30.63,0,0,1,.26,4.44.36.36,0,0,1-.09.23l-.09.07s0,0-.11,0l-.1,0,.06,0H83.1a1.1,1.1,0,0,1-.37-.17,3,3,0,0,1-1.17-1.94,39.64,39.64,0,0,1-.4-4.61c-.08-1.54-.1-3.08-.06-4.64,0-1.86-.19-3.78-.27-5.67L80.61,90l-.11-3.85c-.07-1.94-.1-3.9-.2-5.82-.09-1.5-.31-3-.45-4.46,0-.33-.08-.65-.08-1,0-1.23.2-1.65.78-1.89a2.05,2.05,0,0,1,.38-.16c.4-.1.8.4,1,1.27a52.47,52.47,0,0,1,.81,8.16c.1,2.08.11,4.17.18,6.25Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M99.38,99.27c1-.87,2-1.74,3-2.58.37-.36.2,0,.26-.9l0-2,0-2.85c0-3.35-.09-6.71-.19-10.07,0-1.5-.14-3-.24-4.47-.12-1.9-.29-3.81-.23-5.72,0-1.19,1.2.26,1.43,2.44.33,3.86.71,7.73.72,11.66,0,2.35.23,4.79.29,7.2,0,1.32,0,2.64,0,4v.56a6.71,6.71,0,0,1,0,.78l-1,.87L102,99.52c-1.2,1.08-2.4,2.18-3.58,3.28l-5.4,5c-1.39,1.3-2.7,2.65-4.1,3.92-.31.28-.6.58-.93.84a4.17,4.17,0,0,1-1.41.9,1.26,1.26,0,0,1-.92,0,2.61,2.61,0,0,1-.37-.14c-.31-.18,0-.89.73-1.7,2.39-2.28,5-4.62,7.55-7l5.81-5.37Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M97.45,66.7c1.6-.78,3.18-1.6,4.7-2.49.28-.17.54-.35.8-.53l.36-.25.22-.22a5.67,5.67,0,0,0,1.35-2.64,9.4,9.4,0,0,0,.26-3.22,7.6,7.6,0,0,0-.79-2.78,8.68,8.68,0,0,0-2.3-2.77c-.27-.26-.09-.52.37-.6a2.44,2.44,0,0,1,.9.07,2.87,2.87,0,0,1,1,.61,9.53,9.53,0,0,1,2.33,8.24,11.4,11.4,0,0,1-.72,2.59A5.29,5.29,0,0,1,104.18,65c-1.55,1-3.14,1.94-4.75,2.81-1,.53-2,1-3,1.55-1.51.76-3.07,1.47-4.58,2.22-1.18.57-2.28,1.24-3.45,1.84-.25.13-.49.27-.76.4-1,.43-1.35.42-1.77,0a2.61,2.61,0,0,1-.28-.31c-.26-.38,0-.88.67-1.29A62.35,62.35,0,0,1,92.59,69c1.61-.76,3.24-1.52,4.84-2.35Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M8.53,67.52a11,11,0,0,1,.88-3.32,7.44,7.44,0,0,1,2.19-2.92c.14-.1.22-.19.4-.3a5,5,0,0,1,.66-.32c.36-.11.64-.16,1-.23.56-.07,1.11-.13,1.63-.16,1.05-.07,2.07-.07,3.09-.07,4.07,0,8.07.24,12.08.43l8.76.41c10.28.55,20.57,1.15,30.83,1,2.27-.06,4.55-.17,6.8-.4.57,0,1.13-.12,1.69-.19.26,0,.59-.06.81-.11l.27-.09.36-.16c1-.45,2-1,3-1.54C88,56.71,93.1,53.71,98.69,51.74c1.78-.57,1.66,0,.39.92a50.28,50.28,0,0,1-6.54,4.08c-2.61,1.38-5.19,2.83-7.82,4.25-1.33.71-2.58,1.42-4.1,2.09a5,5,0,0,1-1.42.39l-1.14.13c-.75.09-1.51.14-2.27.21a162.26,162.26,0,0,1-18.05.13c-7.19-.29-14.67-.5-22-.85-4-.19-8.06-.39-12.09-.52-2-.07-4-.11-6-.09-1,0-2,.05-2.94.13L14,62.7c-.2,0-.43.09-.58.14a.26.26,0,0,1-.15,0,1.5,1.5,0,0,1-.23.2,3.12,3.12,0,0,0-.46.43c-1.44,1.56-1.91,4-1.78,6.33a13.3,13.3,0,0,0,.68,3.42,5.64,5.64,0,0,0,.31.81,5.5,5.5,0,0,0,.38.77,4.78,4.78,0,0,0,.44.72l.24.35a2.49,2.49,0,0,0,.23.23,5.76,5.76,0,0,0,2.2,1A22.52,22.52,0,0,0,18,77.7c1.82.27,3.68.4,5.55.49,3.73.17,7.48.15,11.2.06,5.8-.14,11.47-.59,17.21-.85,1.27-.06,2.51-.14,3.78-.18,4.74-.13,6.27.07,7.28.74a5,5,0,0,1,.66.46c.44.53-1.48.9-4.91,1.11-10.21.65-21,1.37-32,1.22-2,0-4.09-.12-6.16-.29a32.23,32.23,0,0,1-6.32-1.06l-.83-.29c-.29-.11-.58-.26-.86-.39s-.6-.37-.89-.56l-.45-.43a2.91,2.91,0,0,1-.36-.42A11.59,11.59,0,0,1,9.25,74.2a15.41,15.41,0,0,1-.78-6.67Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M23.93,55.79c1.19-.26,2.38-.55,3.56-.88.43-.13.84-.3,1.27-.43l4.59-1.34c.67-.2,1.34-.45,2-.7a9.16,9.16,0,0,1,2.59-.79c.29,0,.34.23.23.59a2.18,2.18,0,0,1-.85,1.14,30.82,30.82,0,0,1-5.16,2c-1.09.27-2.14.77-3.22,1.14s-2.4.76-3.61,1.11l-2.25.59c-1.13.29-2.29.52-3.41.82-.87.24-1.7.56-2.57.78-.19,0-.37.11-.57.15-.72.13-1,0-1.22-.38a2.09,2.09,0,0,1-.17-.28c-.13-.33.1-.69.59-.94a18.77,18.77,0,0,1,4.61-1.7l3.57-.89Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M83.9,47.55l3.07.37c.37,0,.75,0,1.12.07l4,.51c.58.07,1.17.09,1.75.11a7.1,7.1,0,0,1,2.24.24c.23.08.2.33,0,.61a1.64,1.64,0,0,1-1,.7A20.69,20.69,0,0,1,90.44,50a22,22,0,0,0-2.82-.16l-3.1-.23-1.91-.14c-1-.07-1.93-.16-2.89-.17-.75,0-1.48.1-2.22.1-.16,0-.32,0-.48,0-.61,0-.79-.18-.91-.63,0-.1-.06-.2-.07-.3-.05-.34.21-.62.66-.74a11.56,11.56,0,0,1,4.1-.46c1,0,2.07.12,3.1.22Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M29.93,80.41c2.52,0,5.06,0,7.59-.07l2.78-.15c3.26-.11,6.54-.2,9.81-.35,1.45-.07,2.91-.17,4.35-.27A51.74,51.74,0,0,1,60,79.39c.58,0,.5.27,0,.53a6.79,6.79,0,0,1-2.42.64c-3.75.3-7.5.68-11.31.85-2.28.09-4.64.39-7,.52-2.57.15-5.14.26-7.72.3-1.58,0-3.17,0-4.76,0a58.51,58.51,0,0,1-7.23-.56,27.49,27.49,0,0,1-2.79-.55,7.75,7.75,0,0,1-2.76-1.22,3.64,3.64,0,0,1-.56-.48L13.12,79A6.48,6.48,0,0,1,12,77.89a.89.89,0,0,1,0-1.14.87.87,0,0,1,.35-.27c.22-.07.41.07.59.13a1.94,1.94,0,0,1,.79.3,4.62,4.62,0,0,1,1.19.93,4.36,4.36,0,0,0,.73.55,8,8,0,0,0,2,.79,27.77,27.77,0,0,0,4.76.83c2.47.24,5,.34,7.56.35Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M98.32,69.93c-.68.33-1.39.6-2.08.89-.25.09-.49.23-.75.32l-2.7.92a11.84,11.84,0,0,0-1.17.46,7.38,7.38,0,0,1-1.49.56c-.33.08-.28-.83.24-1.17a12.88,12.88,0,0,1,3-1.33,12.79,12.79,0,0,0,1.82-.81c.66-.3,1.31-.61,2-.94.39-.2.79-.4,1.18-.63a15.84,15.84,0,0,0,1.7-1.09c.43-.3.77-.71,1.17-1l.25-.22c.35-.25.52-.25.8-.06l.19.14c.19.16.18.44,0,.73a5.42,5.42,0,0,1-.94,1.19,6.87,6.87,0,0,1-1.18,1,20.42,20.42,0,0,1-2,1.15Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M47.11,100.09,47,95.78c0-.53-.09-1-.1-1.57,0-1.86,0-3.72,0-5.59V86.14a8.47,8.47,0,0,1,.38-3.24c.13-.34.43-.17.72.17a2.52,2.52,0,0,1,.62,1.38c0,1,.13,2,.2,3.08s0,2.1,0,3.17a32.28,32.28,0,0,0,.29,3.9l.29,4.32.19,2.66c.1,1.35.17,2.7.34,4,.12,1,.41,2,.56,3.08a6.86,6.86,0,0,1,.12.68c.08.86-.14,1.15-.76,1.35-.14,0-.26.1-.38.12A1.1,1.1,0,0,1,48.3,110a23.77,23.77,0,0,1-.95-5.58c-.12-1.44-.19-2.88-.3-4.33Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M53.42,95.49q-4.05,0-8.09.11c-1,0-2,.12-2.95.14-3.47.08-6.94.16-10.41.34-1.54.09-3.08.23-4.59.4-1.94.22-3.92.56-5.79.64-.56,0-.64-.34-.22-.86a3.47,3.47,0,0,1,1-.79,3.92,3.92,0,0,1,1.51-.53A99.77,99.77,0,0,1,36,94c2.43,0,4.94-.3,7.42-.42q4.08-.17,8.18-.25l5-.08,7.62-.07c2,0,3.89-.19,5.84-.25.43,0,.85,0,1.28,0,1.61,0,2.12.22,2.43.83a2.67,2.67,0,0,1,.2.42c.12.46-.55.82-1.71.91-1.71.13-3.48.26-5.27.27s-3.6,0-5.43.08c-2.7,0-5.43,0-8.15.09Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M97.08,83.65v4c0,.49.06,1,.06,1.45,0,1.71-.05,3.42,0,5.13,0,.76,0,1.52.09,2.27a19,19,0,0,1,0,2.92c-.07.6-.9-.15-1.12-1.23a24.16,24.16,0,0,1-.53-5.89c0-1.19-.17-2.41-.24-3.63s-.11-2.67-.15-4l-.07-2.47c0-1.25,0-2.51-.13-3.75-.06-1-.22-1.9-.31-2.87a4.64,4.64,0,0,1,0-.64c0-.81.28-1.07.74-1.2l.29-.09a.51.51,0,0,1,.45.2,1.4,1.4,0,0,1,.36.65A12,12,0,0,1,96.89,77c.1.87.13,1.75.16,2.64,0,1.33,0,2.67.08,4Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M93,88c.74-.48,1.48-1,2.19-1.53.26-.2.48-.44.74-.64l2.75-2.18c.4-.33.79-.68,1.17-1a8.61,8.61,0,0,1,1.56-1.26c.36-.22.47.74,0,1.29a28.55,28.55,0,0,1-2.88,2.83c-.66.49-1.22,1.13-1.85,1.69s-1.43,1.2-2.18,1.76q-.69.51-1.41,1c-.73.49-1.51.9-2.27,1.34-.6.32-1.16.72-1.79,1a1.4,1.4,0,0,1-.42.18.89.89,0,0,1-.64,0,.87.87,0,0,1-.35-.36,1.73,1.73,0,0,1-.13-.21c-.1-.23.06-.55.35-.88a21.06,21.06,0,0,1,2.93-1.66A26.1,26.1,0,0,0,93,87.91Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M104,87.83s11.84-.09,13.85,5.36c2.43,6.56-15.26,16.41-31.12,19.14L103.66,97Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M62.4,24.22A1.25,1.25,0,0,1,64,23.4C67.25,24.41,61.33,27.67,62.4,24.22Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-2"
|
||||
d="M50.21,11.76a1.24,1.24,0,0,1,1.57-.82C55.06,12,49.14,15.21,50.21,11.76Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-2"
|
||||
d="M26.22,31.38a1.25,1.25,0,0,1,1.57-.82C31.07,31.57,25.15,34.83,26.22,31.38Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-2"
|
||||
d="M93.25,24.22a1.25,1.25,0,0,1,1.57-.82C98.1,24.41,92.18,27.67,93.25,24.22Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-3"
|
||||
d="M38.24,48.36a12.66,12.66,0,0,1-.91-4.4,6.71,6.71,0,0,1,1.6-4.67,6.3,6.3,0,0,1,3.14-1.9,7,7,0,0,1,3.12,0,9.92,9.92,0,0,1,2.65,1.09A18.08,18.08,0,0,1,52,42a39.52,39.52,0,0,1,2.95,3.54,12.46,12.46,0,0,1,2.66,5.34c.09.67-.65.71-1.46.46a3.62,3.62,0,0,1-2.18-1.61,28.08,28.08,0,0,0-6.56-8.29,6.31,6.31,0,0,0-2.7-1.32,4.1,4.1,0,0,0-2.63.29,3.09,3.09,0,0,0-1.78,2.09,7.25,7.25,0,0,0,.08,3.33,10.2,10.2,0,0,0,1.9,3.95,16,16,0,0,0,5.35,4.36,23.83,23.83,0,0,0,5.1,1.81l1.16.28c1.43.39,1.84.67,2,1.49a3.78,3.78,0,0,1,.08.56c0,.59-.73.92-1.88.77a23.58,23.58,0,0,1-10.14-3.91,15.76,15.76,0,0,1-5.69-6.69Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-3"
|
||||
d="M73.11,42.22a9.19,9.19,0,0,0,.68-3.93,1.52,1.52,0,0,0-.45-1A2,2,0,0,0,72,37a4.89,4.89,0,0,0-1.41.33l-.7.24-.7.34a17.84,17.84,0,0,0-4.64,3.37,30.46,30.46,0,0,0-3.86,4.59,27.61,27.61,0,0,0-2.61,4.69c-.93,2.09-1.54,4.28-2.33,6.38-.25.65-1,.45-1.5-.32a4,4,0,0,1-.46-3.51,33.29,33.29,0,0,1,7.89-12.72,44.85,44.85,0,0,1,3.44-3.11,14.16,14.16,0,0,1,4.18-2.45,9.09,9.09,0,0,1,2.75-.57,4,4,0,0,1,4.47,3.91,9.49,9.49,0,0,1-.18,2.74A19.38,19.38,0,0,1,74,46.78a22.94,22.94,0,0,1-6.37,6.88c-1.94,1.43-3.91,2.69-5.83,3.93l-1.25.83c-1.58,1-2.15,1.17-2.91.76a3.53,3.53,0,0,1-.51-.28c-.48-.37-.11-1.23,1-2.13,3.36-2.69,7.31-4.48,10.1-7.23a20.43,20.43,0,0,0,2.8-3.4,16.47,16.47,0,0,0,2-3.94Z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const LightBulbIcon = () => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 128 128"
|
||||
className="w-12 fill-primary"
|
||||
>
|
||||
<title>Free Icons</title>
|
||||
<g
|
||||
id="Layer_49"
|
||||
data-name="Layer 49"
|
||||
>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M62,109a23.62,23.62,0,0,1-5.73-.76,13.32,13.32,0,0,1-2.07-.71A9.7,9.7,0,0,1,51,105.18a9.6,9.6,0,0,1-1.13-1.6,5.1,5.1,0,0,1-.63-2,4.81,4.81,0,0,1,.13-1.85,5.67,5.67,0,0,1,.8-1.66,4.54,4.54,0,0,1,3.94-1.88c.46,0,.39.26.1.62a10.79,10.79,0,0,1-1.2,1.32,5.51,5.51,0,0,0-1,1.12,2.9,2.9,0,0,0-.51,1.22,2.83,2.83,0,0,0-.05,1.33,4.84,4.84,0,0,0,.64,1.48,5.59,5.59,0,0,0,1.51,1.56,11,11,0,0,0,2,1,16.87,16.87,0,0,0,5.12,1,28.47,28.47,0,0,0,3.33,0,21.14,21.14,0,0,0,5-.8,16.56,16.56,0,0,0,3.48-1.48c.25-.13.47-.28.71-.42.89-.52,1.22-.62,1.62-.47a2.14,2.14,0,0,1,.27.09c.22.11.06.62-.56,1.2a14.07,14.07,0,0,1-3.13,2.2,16,16,0,0,1-1.79.8c-.63.2-1.27.36-1.91.5a27.47,27.47,0,0,1-5.77.52Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M67.12,109.72a30,30,0,0,1-3.11.63l-1.15.15a19.19,19.19,0,0,1-4.08-.12c-.6-.08-1.2-.18-1.79-.31a5.83,5.83,0,0,1-2.17-.87c-.2-.15,0-.33.25-.44a1.56,1.56,0,0,1,1,0,16.18,16.18,0,0,0,4.28.85,12.74,12.74,0,0,0,2.75-.16,24.16,24.16,0,0,0,3-.57c.61-.15,1.21-.35,1.81-.54l1.36-.48,1.31-.56c.67-.33,1.28-.72,1.93-1.07L73,106c.53-.29.74-.31,1-.22l.14.06c.12.08,0,.31-.38.62a13.85,13.85,0,0,1-3.55,2.23,18.67,18.67,0,0,1-3,1.1Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M69.12,116.17a4.5,4.5,0,0,0,.86-1.08c.1-.15.13-.34.22-.49a18,18,0,0,0,.87-1.82c.13-.27.23-.57.34-.86a2,2,0,0,1,.66-1.1c.12-.1.25.09.38.32s.27.44.23.63a7.41,7.41,0,0,1-.71,2.15c-.25.42-.35.93-.57,1.4a8.7,8.7,0,0,1-.88,1.49,5.23,5.23,0,0,1-.78.78l-.32.27-.38.2a3.72,3.72,0,0,1-.77.33,3.42,3.42,0,0,1-.61.22,4.64,4.64,0,0,1-.64.17,1.31,1.31,0,0,1-.28,0c-.35,0-.45-.15-.48-.5,0-.08,0-.15,0-.22a.72.72,0,0,1,.36-.58c.63-.31,1.09-.41,1.54-.63a3.77,3.77,0,0,0,.94-.7Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M53.37,98.52a3.31,3.31,0,0,0-.81.42c-.09.07-.14.17-.24.25a4.46,4.46,0,0,0-.91.93,1,1,0,0,0-.13.52c0,.23.08.36-.1.54a2.13,2.13,0,0,1-.88.29c-.41.07-1-.13-1-.41a2.07,2.07,0,0,1,.13-1.28,2.6,2.6,0,0,1,.65-.93c.33-.3.48-.7.77-1A5.77,5.77,0,0,1,51.93,97a5.23,5.23,0,0,1,.79-.38c.2-.09.44-.13.65-.2s.46-.07.69-.09.37-.05.56-.05a2.84,2.84,0,0,1,.58.05.4.4,0,0,1,.23.1c.25.19.26.37.08.73a1.71,1.71,0,0,1-.13.23,1.54,1.54,0,0,1-.56.53c-.56.31-.59.4-.82.46a2.36,2.36,0,0,0-.6.22Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M36.22,81.71a49.21,49.21,0,0,1-6.29-9c-.33-.59-.62-1.2-.9-1.81a17.8,17.8,0,0,1-.8-1.85,31.33,31.33,0,0,1-2.14-13.93c.06-1,.23-2.09.36-3.13s.35-2.06.64-3.06a20.29,20.29,0,0,1,3.16-7.33c.49-.68.53-.51.29.16S29.88,43.6,29.33,45c-.25.61-.46,1.23-.65,1.86s-.33,1.28-.52,1.92a18,18,0,0,0-.45,1.93c-.12.65-.29,1.29-.36,2a31.09,31.09,0,0,0-.19,8A28.89,28.89,0,0,0,29.84,70a44.29,44.29,0,0,0,5.7,9.21,58.71,58.71,0,0,0,4.43,5,99.8,99.8,0,0,0,7.48,6.92c2,1.7,4,3.27,6.07,4.91.44.37.89.71,1.32,1.1,1.62,1.42,2,2,2.21,2.47a2.21,2.21,0,0,1,.12.32c0,.25-.7-.25-1.91-1.23-3.6-2.88-7.51-5.87-11.22-9.15a82.77,82.77,0,0,1-7.84-7.83Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M31.45,39.67a31.31,31.31,0,0,1,5.45-5.58,36.26,36.26,0,0,1,6.63-4A33.3,33.3,0,0,1,64.1,27.69c.91.18,1.83.4,2.73.67s1.79.64,2.68,1a22.87,22.87,0,0,1,8,5.93,27.22,27.22,0,0,1,5,8.49A39.66,39.66,0,0,1,84.41,63a59.78,59.78,0,0,1-1.69,8.4A77.05,77.05,0,0,1,80,79.42a80,80,0,0,1-4.59,9.85,79.92,79.92,0,0,1-5.8,9.16c-1.33,1.82-1.39,1.39-.64-.38.38-.88.93-2.12,1.62-3.59s1.5-3.18,2.45-5c1.69-3.21,3.14-6.53,4.52-9.86A76.26,76.26,0,0,0,81,69.37a44.2,44.2,0,0,0,.63-21.22,30.27,30.27,0,0,0-2.18-6.06,23.37,23.37,0,0,0-3.62-5.34,19.76,19.76,0,0,0-5-4.06,23.39,23.39,0,0,0-6-2.34,31.52,31.52,0,0,0-27.15,6.22A24.28,24.28,0,0,0,32,43.27c-.33.66-.68,1.31-1,2l-.76,2.07a34.32,34.32,0,0,0-1,4.36l-.14.83-.07.85-.13,1.69v2.54l.08.84a29.74,29.74,0,0,0,1.3,6.66,37.55,37.55,0,0,0,2.63,6.28,52.37,52.37,0,0,0,3.63,5.78c4.18,5.72,9.32,10.48,14.6,15.14,1.16,1,2.32,2,3.48,3.08,4.32,3.91,5.49,5.63,5.71,7a3.87,3.87,0,0,1,.08.89c0,.16-.12.15-.29,0s-.36-.41-.73-.77c-.69-.71-1.83-1.83-3.41-3.22-4.74-4.07-9.84-8.2-14.5-13A58.44,58.44,0,0,1,29.61,69.75a37.92,37.92,0,0,1-2.42-7.4,32,32,0,0,1-.62-7.82,33.6,33.6,0,0,1,1.3-7.73,25.94,25.94,0,0,1,3.52-7.16Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M57.3,107.39a23.41,23.41,0,0,0,7.92,0c1-.17,1.94-.44,2.87-.64a19,19,0,0,0,4.64-2,12.83,12.83,0,0,0,3.76-3.28,3.43,3.43,0,0,0,.28-3.76,6,6,0,0,0-2-1.84,15.3,15.3,0,0,0-2.61-1.25c-.57-.19-.49-.38.1-.54a4.65,4.65,0,0,1,2.94.22,7.54,7.54,0,0,1,2.9,2.11,5.67,5.67,0,0,1,.94,1.79,4.41,4.41,0,0,1,.07,2.08,7.14,7.14,0,0,1-1.73,3.32,11.69,11.69,0,0,1-2.6,2.19,31.12,31.12,0,0,1-3.48,2,19.59,19.59,0,0,1-1.88.79c-.31.12-.66.21-1,.31l-1,.21a29,29,0,0,1-8.63.71,19.64,19.64,0,0,1-5.27-1.19A12.61,12.61,0,0,1,50,106.36a7.81,7.81,0,0,1-2.32-3.53,5.91,5.91,0,0,1,0-3.41,6.7,6.7,0,0,1,1.94-2.78,9,9,0,0,1,1.18-.87,4.55,4.55,0,0,1,1.79-.65,1.23,1.23,0,0,1,.94.27,1.34,1.34,0,0,1,.31.26c.24.32-.32.79-1.25,1.38a6,6,0,0,0-2.85,3.28,3.6,3.6,0,0,0,0,1.9,5.63,5.63,0,0,0,1,1.88,11,11,0,0,0,6.51,3.25Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M54.63,102.66a17.26,17.26,0,0,0,4.6,1.17c.59.07,1.18.06,1.77.08a21.85,21.85,0,0,0,6.29-.58,13.07,13.07,0,0,0,2.62-1,11.85,11.85,0,0,0,2.77-2c.26-.24.45-.1.49.33a2.16,2.16,0,0,1-.72,1.75,13,13,0,0,1-7.37,3,37.89,37.89,0,0,1-4.79.34,18.87,18.87,0,0,1-5.25-.83,12.92,12.92,0,0,1-3-1.4,8.26,8.26,0,0,1-1.92-1.72,7.11,7.11,0,0,1-.71-1.1A2.85,2.85,0,0,1,49,99.23a3.87,3.87,0,0,1,.69-2.06,5.75,5.75,0,0,1,1.44-1.47,4.81,4.81,0,0,1,.78-.48c1.07-.48,1.56-.29,1.8.13a1.34,1.34,0,0,1,.15.29c.08.32-.27.62-.78.9a5,5,0,0,0-1.93,1.79,1.7,1.7,0,0,0-.27.91.8.8,0,0,0,.09.3c0,.11.2.35.29.53a7.08,7.08,0,0,0,3.37,2.54Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M60.39,111.81a13.18,13.18,0,0,0,4.18.23,13.75,13.75,0,0,0,1.56-.27,22.55,22.55,0,0,0,5.42-1.64,12.09,12.09,0,0,0,2.16-1.29,18.65,18.65,0,0,0,2.3-2.12c.24-.22.45-.09.56.33a1.92,1.92,0,0,1,0,.81,2.68,2.68,0,0,1-.44.9,13.29,13.29,0,0,1-6,3.88,38.18,38.18,0,0,1-4.19,1.22,17.44,17.44,0,0,1-4.84.23,13.45,13.45,0,0,1-3-.68A11.5,11.5,0,0,1,54.26,111,10.73,10.73,0,0,1,52,108.27c-.12-.24-.24-.47-.34-.71-.29-1-.12-1.31.28-1.6a2.14,2.14,0,0,1,.26-.19c.28-.15.7.14,1.07.65.54.76,1,1.48,1.55,2.14a8.56,8.56,0,0,0,1.89,1.71,10.4,10.4,0,0,0,3.67,1.49Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M71.89,116a8.26,8.26,0,0,1-2,2.11,4.18,4.18,0,0,1-1,.57,3.78,3.78,0,0,1-2,.23,5.32,5.32,0,0,1-1.76-.61c-.46-.25-.91-.5-1.34-.78-.27-.18-.55-.36-.8-.56a3.51,3.51,0,0,1-.61-.77c-.11-.18.08-.33.39-.42a1.71,1.71,0,0,1,1,0,14.14,14.14,0,0,0,2.91,1.62,2.06,2.06,0,0,0,1.75-.26,5.27,5.27,0,0,0,1.63-1.54,12.8,12.8,0,0,0,.81-1.29c.37-.69.75-1.4,1.07-2.14.25-.57.42-1.18.69-1.77.06-.13.11-.26.18-.39.29-.45.53-.5.95-.33.09,0,.18.06.25.1a.82.82,0,0,1,.34.86,13.34,13.34,0,0,1-1.19,3.06c-.39.76-.82,1.55-1.32,2.34Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M54.88,50.43a11.27,11.27,0,0,1,0-1.54l.06-.81L55,47.5c.06-.22.14-.42.2-.63a2.28,2.28,0,0,1,1.7-1.54,2.59,2.59,0,0,1,2.21.68,4.89,4.89,0,0,1,.44.47,2.59,2.59,0,0,1,.32.44,6.82,6.82,0,0,1,.41.74,10.84,10.84,0,0,1,.58,1.44,15.9,15.9,0,0,1,.69,3,20.62,20.62,0,0,1-1.84,11.56,14.49,14.49,0,0,1-1.11,1.9,10.25,10.25,0,0,1-.73.93,8.06,8.06,0,0,1-.93.81,5.94,5.94,0,0,1-4.7.9,11.15,11.15,0,0,1-3.64-1.53,15.38,15.38,0,0,1-2.95-2.44A14,14,0,0,1,43.48,61a13.19,13.19,0,0,1-1.3-3.61,6.59,6.59,0,0,1,.34-4,4.84,4.84,0,0,1,1.3-1.71A3.3,3.3,0,0,1,46,51a5.56,5.56,0,0,1,3.61,1.84,16,16,0,0,1,2.33,3c2.33,3.73,3.64,7.92,4.87,11.94a61,61,0,0,1,2,8A30,30,0,0,1,59,83.93c-.2,1.71-.46,1.44-.72,0L57.73,81c-.26-1.19-.53-2.57-.78-4.06a61.71,61.71,0,0,0-2-7.86c-.79-2.64-1.57-5.26-2.53-7.76a22.33,22.33,0,0,0-3.8-6.84,7.79,7.79,0,0,0-1.32-1.22,2.66,2.66,0,0,0-1.36-.49,1.49,1.49,0,0,0-1.12.48,3.31,3.31,0,0,0-.8,1.34,6.73,6.73,0,0,0,.5,4.3,13,13,0,0,0,2.53,4,13.34,13.34,0,0,0,3.89,2.76,5.33,5.33,0,0,0,4.21.33,4.41,4.41,0,0,0,1.74-1.46,14.17,14.17,0,0,0,1.28-2.29,18.2,18.2,0,0,0,1.36-5.16,18,18,0,0,0-.15-5.34,15,15,0,0,0-.74-2.53,7.69,7.69,0,0,0-.57-1.11,1.15,1.15,0,0,0-.47-.5.46.46,0,0,0-.64.26,1.3,1.3,0,0,0-.11.37,4,4,0,0,0-.11.75A14.08,14.08,0,0,0,57,52.26a16.47,16.47,0,0,0,.93,3.19A5.91,5.91,0,0,0,59.63,58a2.81,2.81,0,0,0,2,.41,4.5,4.5,0,0,0,2-1,8.69,8.69,0,0,0,2.66-4,5.47,5.47,0,0,0,.14-2.32,3.32,3.32,0,0,0-.85-1.92,1,1,0,0,0-1.45.09,5.81,5.81,0,0,0-1.23,2A9.82,9.82,0,0,0,62.4,53,17.79,17.79,0,0,0,62,55a31.91,31.91,0,0,0-.34,3.9,39.91,39.91,0,0,0,.59,7.8c.21,1.13.45,2.23.74,3.35.51,2.09,1,3.43,1.2,4.4a5.33,5.33,0,0,1,.22,2.1,5.43,5.43,0,0,1-.1.72c-.16.55-1.4-.9-2.51-4a40,40,0,0,1-2.19-14.83,36.34,36.34,0,0,1,.4-3.86c.12-.64.2-1.3.35-1.94l.21-1c.1-.37.21-.7.33-1a10,10,0,0,1,1-2,4.22,4.22,0,0,1,2.29-1.84,2.83,2.83,0,0,1,1.84.12,3.2,3.2,0,0,1,1.38,1,5.2,5.2,0,0,1,1.13,2.4,7.88,7.88,0,0,1-.05,3.48,10.15,10.15,0,0,1-1.4,3,10.67,10.67,0,0,1-2.22,2.39,6.26,6.26,0,0,1-3.31,1.36,5.35,5.35,0,0,1-1,0c-.33-.05-.64-.15-1-.23s-.58-.26-.86-.4a4.66,4.66,0,0,1-.83-.64,8.68,8.68,0,0,1-1.73-2.83,20,20,0,0,1-1.37-5.87Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M94.5,52.85c0,.17-.26.1-.62-.11a1.5,1.5,0,0,1-.39-.42,1.71,1.71,0,0,1,0-.38,11.77,11.77,0,0,1,.62-1,2.41,2.41,0,0,1,.56-.63,11.71,11.71,0,0,1,1.36-1,1.14,1.14,0,0,1,.36-.15,4.31,4.31,0,0,0,1.2-.53c.07,0,.14-.06.18-.16a3.35,3.35,0,0,1,1.36-.6,9.8,9.8,0,0,1,1.22,0c.06,0,.11,0,.18,0a.33.33,0,0,0,.37.13,1.73,1.73,0,0,1,.5.07,1,1,0,0,1,.25.22.66.66,0,0,1,0,.41c-.06.1,0,.23,0,.36a.57.57,0,0,1,0,.13,6.13,6.13,0,0,1-.8.71s-.28.11-.55.21a4,4,0,0,0-.61.29c-.06,0-.14,0-.21,0s-.81.46-.84.48c-.18.06-.31.2-.56.13,0,0-.08,0-.11,0a6.56,6.56,0,0,1-.89.41,2.44,2.44,0,0,0-.43.28l-.1,0a.35.35,0,0,0-.11,0,5.82,5.82,0,0,0-1,.72c-.06.06-.53.21-.6.3S94.5,52.78,94.5,52.85Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M84.86,30.57c0,.18-.27.1-.64-.12a1.48,1.48,0,0,1-.41-.43,1.94,1.94,0,0,1,0-.4c0-.07.43-.84.58-1.12a2.69,2.69,0,0,1,.53-.7c.42-.4.86-.77,1.3-1.13a.91.91,0,0,1,.34-.17,2.78,2.78,0,0,0,1.09-.65c.06-.05.12-.08.13-.18s.91-.84,1.05-.87c.37-.08.71-.21,1.06-.32.06,0,.08-.07.18,0s.29,0,.39,0a2,2,0,0,1,.45-.16,1,1,0,0,1,.35.08c.11,0,.29.31.3.35s.15.22.24.32l.1.11a4.6,4.6,0,0,1-.37,1.2s-1,.94-1.11,1.06-.15.07-.24.08-.81.75-.85.76c-.19.1-.32.29-.61.24-.06,0-.09,0-.12.05a5.22,5.22,0,0,1-1,.53c-.16.09-.29.22-.44.32a.38.38,0,0,1-.1,0,.33.33,0,0,0-.13,0,9.42,9.42,0,0,0-1,.76,6.13,6.13,0,0,0-.64.3S84.87,30.49,84.86,30.57Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M58.4,19.23c.11.16-.11.3-.5.43a1.33,1.33,0,0,1-.56,0,2.12,2.12,0,0,1-.31-.26c-.05-.05-.35-.9-.5-1.17a3.71,3.71,0,0,1-.26-.82c-.12-.56-.29-1.1-.39-1.65a1.21,1.21,0,0,1,0-.38,2.52,2.52,0,0,0-.13-1.28c0-.07,0-.15-.13-.2a2.76,2.76,0,0,1-.38-1.39,8.58,8.58,0,0,0,.19-1.22c0-.06,0-.11,0-.18s.13-.27.14-.4a2,2,0,0,1,.08-.53c.06-.1.18-.22.25-.32a.42.42,0,0,1,.31-.09c.1.06.19,0,.28-.06l.1,0a3.65,3.65,0,0,1,1.09.85s.15.34.31.7a7.8,7.8,0,0,0,.37.8c.05.08,0,.18,0,.27s.39,1.14.39,1.19c0,.24.13.47,0,.74a.16.16,0,0,0,0,.15,6.51,6.51,0,0,1,.05,1.25c0,.22,0,.42,0,.64a.84.84,0,0,1,0,.12,1,1,0,0,0,0,.14c0,.5-.06,1,0,1.5,0,.12-.2.67-.17.8S58.35,19.17,58.4,19.23Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M26,21c-.21,0-.1-.32.21-.74a2.42,2.42,0,0,1,.56-.46l.44-.06c.07,0,.8.4,1.08.48a2.35,2.35,0,0,1,.67.39l1.28.9a.78.78,0,0,1,.25.26,2.21,2.21,0,0,0,1,.78c.07,0,.12.08.22.05a3.43,3.43,0,0,1,1.25.66,11.21,11.21,0,0,0,.77.91s.11,0,.1.16.1.28.19.36a1.55,1.55,0,0,1,.35.37,1.09,1.09,0,0,1,.07.36c0,.12-.21.4-.25.42s-.15.23-.22.36a.57.57,0,0,1-.08.13,4.23,4.23,0,0,1-1.24.07L32,26.11c-.34-.14-.7-.28-.78-.3s-.13-.11-.18-.18-1.09-.43-1.13-.47-.43-.19-.52-.5c0-.05-.06-.07-.1-.09a5.07,5.07,0,0,1-1-.77,6.13,6.13,0,0,0-.51-.38s0-.07-.07-.1a.29.29,0,0,0-.08-.13c-.4-.31-.7-.73-1.12-1-.11-.06-.32-.64-.43-.72S26.1,21,26,21Z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const WalletIcon = () => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 128 128"
|
||||
className="w-12 fill-primary"
|
||||
>
|
||||
<title>Free Icons</title>
|
||||
<g
|
||||
id="Layer_21"
|
||||
data-name="Layer 21"
|
||||
>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M59.87,118c-4,.68-8.08,1.46-12.24,1.85A36.91,36.91,0,0,1,35,119.22a16.72,16.72,0,0,1-8.31-4.74,17.79,17.79,0,0,1-3.9-7.45,77.46,77.46,0,0,1-1.46-7.9c-.72-5.26-1.09-10.52-1.55-15.75a136.6,136.6,0,0,0-1.81-13.8c-.53-2.91-1.13-5.81-1.88-8.66-.19-.71-.38-1.42-.59-2.13s-.37-1.42-.55-2.13c-.42-1.41-.87-2.81-1.38-4.2-.7-1.69-.56-1.52.44-.25a25.18,25.18,0,0,1,3.87,7.09,91,91,0,0,1,2.26,9c.57,3,1,6.06,1.37,9.11.71,6.1,1,12.19,1.68,18.22a71.88,71.88,0,0,0,1.93,10.8,17.49,17.49,0,0,0,2.17,4.77,13.34,13.34,0,0,0,3.63,3.63c3.17,2.1,7.2,2.81,11.19,2.86a69.24,69.24,0,0,0,12.11-1.16l7.48-1.29c2.47-.46,4.94-1,7.39-1.59,3.71-.91,7.41-1.93,11-3.09a80.37,80.37,0,0,0,10.59-4.11,28.19,28.19,0,0,0,3.72-2.15,8,8,0,0,0,2.68-2.76A15.26,15.26,0,0,0,98,97.57a26.4,26.4,0,0,0,.13-4.18c-.07-1.23-.21-2.44-.38-3.68-.65-4.59-1.14-5.95-.49-7.24a6.47,6.47,0,0,1,.28-.82c.23-.61,1.91,1,2.77,4.58a38.31,38.31,0,0,1,.78,4.06,34.2,34.2,0,0,1,.25,4.2,29,29,0,0,1-.39,4.32l-.23,1.09-.3,1.1a10.39,10.39,0,0,1-1,2.35,12.42,12.42,0,0,1-3.57,3.32,33.67,33.67,0,0,1-3.83,2.13,73.9,73.9,0,0,1-7.91,3.14c-4,1.34-8,2.45-12,3.45s-8.11,2-12.23,2.66Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M87.47,31.43a12.15,12.15,0,0,0-4.86-.13,46.31,46.31,0,0,0-5.13,1.28c-3.45,1-6.88,2.23-10.3,3.44L59.7,38.76c-4.41,1.56-8.84,3.1-13.32,4.53A141.12,141.12,0,0,1,32.76,47a61.74,61.74,0,0,1-6.23,1,23.19,23.19,0,0,1-6.39,0l-1-.21c-.34-.09-.68-.22-1-.33a5.19,5.19,0,0,1-1-.46c-.16-.09-.32-.17-.48-.27a3.56,3.56,0,0,1-.48-.39,3.06,3.06,0,0,1-.75-1A3.26,3.26,0,0,1,15.14,44a5.23,5.23,0,0,1,.56-2.21,12.57,12.57,0,0,1,2.48-3.37,16.58,16.58,0,0,1,3.22-2.55c.75-.43,1.19-.46,1.2-.33s-.29.44-.76,1a31.83,31.83,0,0,0-4.06,5.32c-.6,1-.87,2.21-.55,2.68a1.8,1.8,0,0,0,1,.71l.35.2.41.13a5.72,5.72,0,0,0,.83.26,22.12,22.12,0,0,0,7.58.05A114.35,114.35,0,0,0,43,42.25c6.24-1.8,12.57-4.23,18.83-6.5,3.45-1.24,6.9-2.49,10.39-3.67,1.75-.59,3.5-1.15,5.28-1.68A33.49,33.49,0,0,1,83,29.15a11.4,11.4,0,0,1,7.06,1.07,9.19,9.19,0,0,1,2.71,2.48,13,13,0,0,1,1.58,3.22A35.21,35.21,0,0,1,95.7,46.26c0,3.45-.09,6.86,0,10.23q0,2,.24,3.87a16,16,0,0,0,.31,1.86c.06.31.16.6.23.89l.07.22.11.32c.07.21.13.43.18.65a1.14,1.14,0,0,1-.38,1.24,3.6,3.6,0,0,1-1.26.71,13.22,13.22,0,0,1-2,.48c-1.32.22-2.62.36-3.92.5l-3.39.38c-4.22.44-5.39.72-6.35.8-.22,0-.49.11-.64.12s-.16-.06-.08-.23a2.19,2.19,0,0,1,.64-.67,10.35,10.35,0,0,1,3.49-1.46A61.09,61.09,0,0,1,90,65.06c1.17-.16,2.35-.31,3.44-.55.27-.05.53-.12.78-.19a1.77,1.77,0,0,0,.31-.11h0s.06,0,0-.16l0,0a.46.46,0,0,1,0-.12l-.13-.49a9.22,9.22,0,0,1-.23-1c-.14-.65-.21-1.29-.29-1.93-.13-1.28-.2-2.54-.22-3.79-.06-2.5,0-5,0-7.42a52.54,52.54,0,0,0-.72-10.65A13.24,13.24,0,0,0,91.08,34a6.16,6.16,0,0,0-3.61-2.55Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M91.62,78.84c1.25-.25,2.49-.55,3.72-.86l1.84-.51L98.81,77l.17,0a.32.32,0,0,0,0-.17l0-.28,0-.73a12.57,12.57,0,0,1,0-1.36l.13-1.26.24-2.47c.14-1.64.25-3.29.29-4.94a28.3,28.3,0,0,0-.19-4.33,11.37,11.37,0,0,0-.62-2.57,2.55,2.55,0,0,0-.58-.91.8.8,0,0,0-.82-.18c-.43.14-.63-.14-.26-.69a1.45,1.45,0,0,1,1.34-.51,2.4,2.4,0,0,1,1.68,1.24,10.22,10.22,0,0,1,1,3.07,25.87,25.87,0,0,1,.35,3,35.06,35.06,0,0,1-.17,5.89c-.11,1.16-.18,2.35-.24,3.54,0,.61-.08,1.2-.07,1.72,0,.27,0,.55,0,.83l.07,1a3.67,3.67,0,0,1-.2,1.53c-.43.25-.93.44-1.39.65-.7.25-1.28.44-1.92.64q-1.89.59-3.81,1.08c-1.57.41-3.15.77-4.75,1.08a34.13,34.13,0,0,1-3.69.52,13.55,13.55,0,0,1-1.92.06,4.59,4.59,0,0,1-2.13-.52,7.71,7.71,0,0,1-2.13-2.31,16.08,16.08,0,0,1-1.36-2.64,9.89,9.89,0,0,1-.46-1.22,4,4,0,0,1-.2-1.75,1.26,1.26,0,0,1,.65-.83,1.75,1.75,0,0,1,.42-.23.68.68,0,0,1,.68.28,2.7,2.7,0,0,1,.62,1.07,21,21,0,0,0,1.92,4.16,4.82,4.82,0,0,0,1.2,1.39l0,0h0l-.2.31h0l.07-.1.13-.2h0l0,0c.07,0,.24,0,.36.07s.34,0,.5,0a4.86,4.86,0,0,0,.54,0,26.48,26.48,0,0,0,3.63-.4c1.24-.2,2.49-.47,3.74-.75Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M77,19.55a8,8,0,0,0-1.33-1.93c-.21-.19-.45-.31-.66-.48a4.19,4.19,0,0,0-2.68-.93,4.4,4.4,0,0,0-1.42.35,4.17,4.17,0,0,1-1.9.5c-.45,0-.68-2.38.12-2.63a17.14,17.14,0,0,1,2.11-.53,7.87,7.87,0,0,1,1.29-.05,5,5,0,0,1,1.28.27,8.87,8.87,0,0,1,2.78,1.25,8.11,8.11,0,0,1,2.08,2.35,14.28,14.28,0,0,1,.86,1.64c.4.83.64,1.71.95,2.55.23.66.57,1.28.8,1.95a2.26,2.26,0,0,1,.17.43c.13.57,0,.77-.62,1l-.43.14a1,1,0,0,1-1.12-.4,19.07,19.07,0,0,1-1.32-3.16,16.37,16.37,0,0,0-1-2.25Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M27.21,34.77c.28.79.57,1.59.89,2.38.11.29.27.56.38.85l1.16,3.09c.17.46.38.91.59,1.35a6.13,6.13,0,0,1,.66,1.76c.06.39-1.34.41-1.65-.21a21.48,21.48,0,0,1-1.4-3.5,19.15,19.15,0,0,0-.92-2.14c-.34-.79-.67-1.6-1-2.4-.19-.5-.39-1-.58-1.49-.3-.75-.55-1.52-.86-2.27-.23-.58-.55-1.12-.79-1.7a2.19,2.19,0,0,1-.17-.38c-.16-.49-.09-.68.3-.89l.27-.15a.66.66,0,0,1,.84.31,15.36,15.36,0,0,1,1.41,3c.29.78.6,1.57.9,2.36Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M49,17.22c-2.08.83-4.18,1.61-6.27,2.4-.76.29-1.5.63-2.27.91-2.69,1-5.4,2-8.07,3C31.2,24,30,24.48,28.88,25c-1.45.68-2.95,1.41-4.26,2.08-.27.16-.63,0-.5-.63a3.16,3.16,0,0,1,1.56-1.8,62.43,62.43,0,0,1,9.26-3.9c1.9-.65,3.79-1.52,5.68-2.28L46.89,16c1.28-.51,2.57-1,3.84-1.56,1.93-.82,3.87-1.63,5.73-2.54,1.45-.7,2.8-1.52,4.19-2.29l.91-.5c1.15-.61,1.58-.68,2-.49a2,2,0,0,1,.29.12c.24.14-.07.68-.84,1.31a35.38,35.38,0,0,1-7.76,4.55c-2.06.94-4.16,1.81-6.24,2.68Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M67.68,24.37c-.34-1-.7-2.09-1.07-3.12-.14-.38-.34-.73-.48-1.11l-1.39-4.06A16.67,16.67,0,0,0,64,14.34a5.9,5.9,0,0,1-.87-2.3c0-.53,2.38-.71,2.71.1a27.47,27.47,0,0,1,1.55,4.64,20.42,20.42,0,0,0,1.1,2.83c.4,1.05.78,2.1,1.15,3.16l.69,2c.35,1,.65,2,1,3,.28.77.69,1.47,1,2.23a5.44,5.44,0,0,1,.22.5c.2.65.1.9-.5,1.18-.13.06-.26.13-.4.18a1,1,0,0,1-1.18-.41,21,21,0,0,1-1.75-3.91c-.37-1-.74-2-1.12-3.08Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M59.88,20.52H59.8l-.59.17c-.41.11-.81.25-1.22.38-.81.28-1.62.58-2.43.91-.6.24-1.16.54-1.77.78-2.11.85-4.3,1.66-6.52,2.34l-2.94,1a11.7,11.7,0,0,1-3.88.82c-.82,0-.16-2.48,1.19-2.77,2.45-.58,4.86-1.26,7.39-2a38.41,38.41,0,0,0,4.46-1.83A52.69,52.69,0,0,1,58.6,18.4l.53-.15.75-.21,1.49-.38L62,19.4c.56,1.63,1.13,3.26,1.68,4.88.44,1.21,1,2.37,1.44,3.59.1.27.21.53.3.81.3,1,.21,1.41-.37,1.76a2.3,2.3,0,0,1-.4.23c-.46.2-.94-.13-1.26-.81-.94-2-1.72-4.23-2.52-6.46l-.73-2.07L60,20.8l0-.13h0v-.06h0Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M32.91,35.71l.42,1.42c.05.18.15.33.19.51.17.63.32,1.26.5,1.89a6.19,6.19,0,0,0,.32.81,2,2,0,0,1,.34,1.06c0,.25-1.37.38-1.53,0a8.16,8.16,0,0,1-.66-2.08A6.88,6.88,0,0,0,32,38.07c-.19-.47-.32-1-.47-1.45l-.27-.91c-.15-.45-.24-.92-.4-1.37s-.31-.66-.44-1a.83.83,0,0,1-.08-.22c-.06-.3,0-.42.29-.56l.18-.09a.56.56,0,0,1,.61.15,5.5,5.5,0,0,1,1,1.71c.21.44.33.92.5,1.38Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M33.7,35.9c.13.4.25.8.37,1.2,0,.15.13.28.17.43.14.52.28,1.07.42,1.59a5.46,5.46,0,0,0,.26.67,1.91,1.91,0,0,1,.29.89c0,.21-1.13.32-1.26,0A6.74,6.74,0,0,1,33.4,39,5.4,5.4,0,0,0,33,37.88c-.15-.39-.27-.8-.4-1.21l-.24-.75c-.14-.38-.23-.77-.37-1.14s-.29-.54-.4-.82a1.08,1.08,0,0,1-.08-.19c-.06-.24,0-.34.21-.47l.15-.08a.43.43,0,0,1,.5.1,4.43,4.43,0,0,1,.93,1.41,11.6,11.6,0,0,1,.45,1.16Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M85.33,74.08c.25-.06.45-.13.52-.44a.88.88,0,0,0-.08-.39l-.06-.37a1.16,1.16,0,0,0-.21-.34,2,2,0,0,0-.82-.61.93.93,0,0,0-.77,0c-.21.15-.22.29-.42.69-.07.11-.45.16-.84,0a1.44,1.44,0,0,1-.55-.38.87.87,0,0,1-.12-.71,2.24,2.24,0,0,1,.93-1.24,2.78,2.78,0,0,1,1.3-.43,3.22,3.22,0,0,1,2.16.56,7.3,7.3,0,0,1,1.07.9,4.61,4.61,0,0,1,.72,1.19,3.25,3.25,0,0,1-.48,3,3.36,3.36,0,0,1-1.46,1.06,3.31,3.31,0,0,1-2.72-.08A3,3,0,0,1,82,74.93a2.21,2.21,0,0,1-.16-.52c0-.58.21-.77.91-.8.16,0,.32,0,.48,0a2,2,0,0,1,1.14.41c.06.06.12.13.17.17l.13,0a.48.48,0,0,0,.18,0c.08,0,.08-.07.08-.07s0,0,.06,0a.82.82,0,0,0,.32-.12Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M84.86,74.27c.12,0,.15-.27.09-.49s-.1-.11-.13-.19a2.51,2.51,0,0,0-.42-1,.35.35,0,0,0-.28-.14c-.05,0-.11.16-.25.1a2.42,2.42,0,0,1-.51-.73c-.22-.4-.27-.92,0-1.07a1.4,1.4,0,0,1,.33-.15,1.61,1.61,0,0,1,.44,0,2.56,2.56,0,0,1,.7,0,1.73,1.73,0,0,1,.94.55c.26.31.66.43.91.75a3.77,3.77,0,0,1,.65,1.19,2.88,2.88,0,0,1,.15,1,2.12,2.12,0,0,1-.76,1.48c-.27.25-.51.59-.78.8a1.39,1.39,0,0,1-.19.15c-.12,0-.21,0-.31-.17a3.12,3.12,0,0,1-.15-.39c0-.1-.07-.22-.11-.35l-.09-.33a3.06,3.06,0,0,1-.07-.55l0-.41A1,1,0,0,1,85,74a1.31,1.31,0,0,0,.07-.55,3,3,0,0,0,.29.44l.15.16a.39.39,0,0,0,.1.08c.17.08-.14-.09-.73.12Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M88,81.45a24.29,24.29,0,0,0,2.53-.32c.31,0,.61-.17.92-.23,1.09-.21,2.19-.46,3.28-.75a14.12,14.12,0,0,0,1.43-.48A5.67,5.67,0,0,1,98,79.14c.41,0,.25,1.26-.39,1.56a18.45,18.45,0,0,1-3.76,1.15c-.79.14-1.55.47-2.35.67a26.12,26.12,0,0,1-2.66.55c-.56.07-1.12.15-1.69.18s-.85,0-1.29,0a11.53,11.53,0,0,1-1.31-.09,6.28,6.28,0,0,1-1-.16c-.17,0-.35-.06-.52-.11l-.5-.23c-.14-.08-.3-.13-.43-.22-.47-.42-.53-.64-.34-1,0-.08.09-.16.14-.23a.77.77,0,0,1,.83-.16,16.89,16.89,0,0,0,2.85.39,9.24,9.24,0,0,0,1.18,0A10.46,10.46,0,0,0,88,81.41Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M26.49,53.14l-1.13.11c-.14,0-.27,0-.41,0-.5,0-1,0-1.48,0h-.65a2.31,2.31,0,0,1-.83-.1c-.17-.06.12-.49.41-.5.52,0,1,0,1.59,0a4.63,4.63,0,0,0,1-.14l1.1-.16.68-.12c.34-.07.69-.12,1-.22s.51-.17.77-.25l.17-.06c.21,0,.29,0,.38.19a.75.75,0,0,1,.06.13.31.31,0,0,1-.15.39,3.64,3.64,0,0,1-1.38.57l-1.12.19Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M76.44,40l-1.17.15-.43.08c-.5.06-1,.12-1.51.21-.23,0-.44.1-.66.16a3.52,3.52,0,0,1-.84.19c-.19,0-.09-.49.22-.62a8.37,8.37,0,0,1,1.69-.49,7.83,7.83,0,0,0,1.05-.3c.38-.1.78-.18,1.17-.26l.72-.15,1.1-.22c.28-.05.55-.17.83-.24l.18,0c.23-.05.32,0,.4.22a.94.94,0,0,1,.06.15.38.38,0,0,1-.17.43,4.88,4.88,0,0,1-1.47.57L76.45,40Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M44.57,49.43l-.77.07-.28,0c-.33,0-.67.06-1,.11a3.34,3.34,0,0,0-.43.1,2.07,2.07,0,0,1-.55.11c-.12,0-.06-.34.14-.42a4.77,4.77,0,0,1,1.12-.31,5.84,5.84,0,0,0,.69-.18c.25-.07.51-.11.77-.16l.48-.08.72-.13c.18,0,.36-.11.54-.16l.12,0c.15,0,.2,0,.26.16l0,.1a.26.26,0,0,1-.11.3,3,3,0,0,1-1,.38l-.76.1Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M99.49,91s12.18-.88,14.94,4.77c3.94,8-25.72,15.38-33.94,17-9.44,1.85-7.43,1.59-7.43,1.59s20.5-5.4,23.43-9.41S100.21,93.08,99.49,91Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M54.63,40.73c-3.88,1.28-7.8,2.5-11.75,3.6-1.45.4-2.89.83-4.35,1.18a68.56,68.56,0,0,1-7.85,1.4,23.57,23.57,0,0,1-8.11-.21,13.8,13.8,0,0,1-1.79-.58,7.26,7.26,0,0,1-1.69-1.06,3,3,0,0,1-.93-2,4.66,4.66,0,0,1,.34-2,11.58,11.58,0,0,1,2.65-3.89,13.82,13.82,0,0,1,3.71-2.75c.95-.39.89,0,.39.66a37.37,37.37,0,0,1-2.4,3,14.52,14.52,0,0,0-2.31,3.36A3.21,3.21,0,0,0,20.19,43a1.13,1.13,0,0,0,.6.86A8.58,8.58,0,0,0,24.51,45a26,26,0,0,0,4.34.11,55.22,55.22,0,0,0,10.81-2c3.94-1,7.85-2.22,11.75-3.49,2.39-.79,4.79-1.59,7.17-2.43,3.6-1.28,7.23-2.56,10.79-3.89,2.76-1,5.44-2.17,8.21-3.14.61-.22,1.21-.44,1.83-.64,2.33-.69,3.16-.61,3.76-.36a2.16,2.16,0,0,1,.4.18c.29.24-.59.74-2.18,1.48-2.39,1-4.87,2-7.39,3l-7.7,2.89q-5.77,2.11-11.65,4.13Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M29.58,115.23a12.62,12.62,0,0,0,3.25,2.11c.42.23.9.32,1.34.51a13.16,13.16,0,0,0,5,.86,23.41,23.41,0,0,0,2.34-.22,11.87,11.87,0,0,1,3.1-.13c.32,0,.27.34,0,.66a2.17,2.17,0,0,1-1.27.75,19.94,19.94,0,0,1-6.33.4,23.32,23.32,0,0,1-3.95-.83,15.21,15.21,0,0,1-3.92-2c-.36-.28-.72-.56-1.07-.85s-.67-.61-1-.93a13.86,13.86,0,0,1-2.39-3.34,12,12,0,0,1-1.23-2.93c-.05-.23-.11-.45-.15-.69-.1-.88.08-1.17.46-1.36a2,2,0,0,1,.28-.11c.3-.08.6.25.77.78s.31.79.44,1.18l.52,1.14a14.06,14.06,0,0,0,1.26,2.15,13.81,13.81,0,0,0,2.52,2.84Z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const ChartIcon = () => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 128 128"
|
||||
className="w-12 fill-primary"
|
||||
>
|
||||
<title>Free Icons</title>
|
||||
<g
|
||||
id="Layer_10"
|
||||
data-name="Layer 10"
|
||||
>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M21.55,80.68c.08-4.89.14-9.73.08-14.61l-.11-5.33c-.07-6.26-.16-12.52-.39-18.78-.1-2.78-.27-5.57-.5-8.31-.33-3.52-.62-7.07-.9-10.53-.07-1.08.21-1,.77-.19a10.42,10.42,0,0,1,1.64,4.58A107.94,107.94,0,0,1,23,38.41q.24,5.45.26,10.93c0,4.37.25,8.92.33,13.39.09,4.91.13,9.84.08,14.76,0,3-.06,6,0,9.06.05,4.57.13,9.16.5,13.67.29,3.51.81,6.92,1.4,10.34.14.75.27,1.49.41,2.24.49,2.82.54,3.73,0,4.45a3.13,3.13,0,0,1-.35.48c-.43.36-1-.72-1.54-2.78a104.72,104.72,0,0,1-2.42-19.44c-.23-4.94-.19-9.89-.18-14.82Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M49.41,104.67c4.89.25,9.8.35,14.7.3,1.79,0,3.57-.14,5.36-.17,6.3-.16,12.61-.54,18.87-1.26,2.78-.33,5.56-.77,8.29-1.27,1.75-.35,3.5-.69,5.24-1.1s3.5-.68,5.26-1c1.1-.18,1,.13.22.72A15,15,0,0,1,103,103c-3.58.92-7.22,1.54-10.87,2.12s-7.33.88-11,1.08c-4.43.27-9,.68-13.55.81q-7.45.24-14.93,0c-3.06-.1-6.12-.23-9.18-.42l-13.84-1c-3.57-.25-7.07-.39-10.61-.67-.77-.07-1.54-.1-2.32-.19-2.9-.31-3.8-.63-4.32-1.38a2.82,2.82,0,0,1-.34-.51c-.2-.56,1-.81,3.14-.68,6.27.4,12.85.93,19.5,1.42,4.95.36,9.87.79,14.81,1Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M34.75,75.38c0,2.72,0,5.45,0,8.17l.11,3c.09,3.5.14,7,.49,10.46,0,.36.09.73.16,1.07,0,.12,0,.19.07.28s.07.18.17.19a1.35,1.35,0,0,0,.29,0,4.41,4.41,0,0,0,.53,0c.37,0,.77,0,1.15,0,1-.07,1.94-.22,2.91-.35s2-.2,2.93-.31c.57-.06.62.25.18.72A5.16,5.16,0,0,1,41.27,100c-1,.17-1.94.32-2.93.43-.5,0-1,.09-1.52.1a7.6,7.6,0,0,1-.82,0,3.49,3.49,0,0,1-.66-.11c-.22-.06-.44-.11-.66-.19-.89-.41-1-2-1-2.27-.07-.56-.12-1.11-.16-1.66-.07-1.09-.1-2.17-.11-3.26,0-2.47-.22-5-.28-7.52C33,82.7,33,79.94,33,77.18l.07-5.09c0-1.29.07-2.58.14-3.87,0-.65.07-1.29.14-1.94a8.62,8.62,0,0,1,.15-1.11c.08-.43.22-.9.67-1a3.41,3.41,0,0,1,1,0l.77.06,1.46.13a25.11,25.11,0,0,0,2.87,0c.41,0,.81,0,1.21-.09,1.47-.17,1.76-.28,2.26-.13.11,0,.25,0,.35.06s.18.25,0,.56a2.77,2.77,0,0,1-1.33.88,14.22,14.22,0,0,1-5.64.31l-1.38-.12-.61,0h0s0,0,0,0c-.05.41-.09.86-.12,1.31-.15,2.67-.19,5.44-.19,8.18Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M44.13,80.37l-.1,3.7c0,.45,0,.9,0,1.35,0,1.58-.11,3.17-.13,4.75,0,.71,0,1.41.07,2.11l.1,1.34A7.93,7.93,0,0,1,44,94.93a.28.28,0,0,1-.08.12l-.06,0h0l-.13.05-.06,0c.13,0,.07,0,0,0h-.11a.68.68,0,0,1-.23-.11,2,2,0,0,1-.85-1.17,30,30,0,0,1-.06-5.53c.09-1.11,0-2.25,0-3.39l0-3.73,0-2.3c0-1.16,0-2.32,0-3.48,0-.89-.15-1.77-.22-2.66,0-.2,0-.39-.05-.59,0-.74.12-1,.61-1.11a2,2,0,0,1,.33-.08c.37,0,.67.26.75.78a30,30,0,0,1,.3,4.88l0,3.72Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M56.93,68c0,3.21,0,6.43.09,9.64l.12,3.52c.09,4.13.17,8.27.41,12.38.06.92.13,1.83.24,2.73l.09.66.06.33,0,.18c0,.09,0,.23.14.27a1.12,1.12,0,0,0,.32,0h.73l.84,0,1.72-.18c1.14-.16,2.31-.22,3.44-.35.68-.08.72.23.18.72a6.51,6.51,0,0,1-3,1.4,26,26,0,0,1-3.74.37l-.31,0a3.4,3.4,0,0,1-.45,0,4.21,4.21,0,0,1-.81-.23c-.1-.08-.27-.09-.32-.24a3.7,3.7,0,0,1-.28-.28,2.51,2.51,0,0,1-.31-.79l-.08-.43,0-.25L56,96.87,55.88,96c-.19-2.44-.24-4.84-.25-7.26,0-2.9-.21-5.9-.27-8.85q-.11-4.87-.13-9.74v-6c0-3,0-6.06.16-9.09a13,13,0,0,1,.18-2,1.36,1.36,0,0,1,.21-.54.89.89,0,0,1,.49-.23,5.26,5.26,0,0,1,1.2,0c1.16.11,2.28.22,3.4.25.49,0,1,0,1.45,0A14.79,14.79,0,0,1,65,52.39c.12,0,.27,0,.38,0s.2.26-.07.61a3.06,3.06,0,0,1-1.62.93c-2.24.56-4.5.16-6.52,0A37,37,0,0,0,57,58.24c0,3.22,0,6.47,0,9.72Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M65.74,73.72,65.67,79c0,.64,0,1.28,0,1.92l-.09,6.73c0,1,0,2,.08,3l.11,1.9a14.12,14.12,0,0,1-.09,1.87.48.48,0,0,1-.07.18s0,.07-.29.14l.12,0H65.4l-.1,0a.71.71,0,0,1-.24-.16,3.22,3.22,0,0,1-.85-1.67,61.8,61.8,0,0,1-.1-7.82c.09-1.57,0-3.19,0-4.8V71.65c0-1.64,0-3.29,0-4.92,0-1.27-.17-2.51-.25-3.77,0-.27,0-.55-.06-.83,0-1,.12-1.39.6-1.58.11,0,.22-.1.33-.13.38-.07.67.36.75,1.09a60,60,0,0,1,.37,6.93v5.28Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M79.38,59.1q0,5.84.16,11.67L79.69,75c.12,5,.25,10,.5,15,.11,2.21.3,4.45.58,6.59,0,.25,0,.29.07.4s0,.2.17.2l.2,0h.26l.85,0c.58,0,1.16-.08,1.75-.15,1.17-.11,2.36-.2,3.53-.34.81-.11.83.21.16.73a8.66,8.66,0,0,1-3.63,1.45c-.59.08-1.18.14-1.79.19-.3,0-.62,0-.94,0a6.43,6.43,0,0,1-.77-.05,7.69,7.69,0,0,1-.79-.21c-.1-.08-.23-.12-.29-.24a.7.7,0,0,1-.26-.28,2.43,2.43,0,0,1-.27-.77l-.09-.43,0-.25-.06-.45c-.08-.6-.15-1.18-.19-1.77-.1-1.17-.16-2.34-.22-3.5-.1-2.34-.16-4.67-.18-7,0-3.5-.26-7.13-.35-10.7-.1-3.92-.16-7.85-.2-11.78l0-7.25c0-3.66,0-7.34.17-11,0-.88.07-1.75.14-2.64l.06-.66,0-.34c0-.16.06-.32.09-.48a2.1,2.1,0,0,1,.34-.84.79.79,0,0,1,.77-.27c.92.13,1.29.18,1.83.24s1,.11,1.55.14,1.18.06,1.77.07a17.79,17.79,0,0,0,2.2-.09c.44,0,.65,0,.94-.08a1.79,1.79,0,0,0,.39-.13c.09,0,.16,0,.18.13a.88.88,0,0,1-.18.6,3.11,3.11,0,0,1-2,1.06,14.18,14.18,0,0,1-3.37.15c-.56,0-1.11-.1-1.66-.17s-1.36-.2-1.17-.15c0,0,0,0,0,.06s0,0,0,.08l0,.52c-.07.7-.1,1.44-.14,2.19-.06,1.48-.09,3-.11,4.52,0,3.89,0,7.83,0,11.75Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M88.36,64.82l-.09,7.39,0,2.69c0,3.17-.07,6.34-.11,9.51,0,1.4,0,2.81.07,4.21,0,.89.07,1.79.1,2.69s0,1.82-.09,2.65a.61.61,0,0,1-.08.26l-.07.08,0,0-.17.06s0,0,0,0c.21-.07.08,0,.1,0h0l-.1,0a.89.89,0,0,1-.24-.24,5.47,5.47,0,0,1-.84-2.38c-.17-3.66-.23-7.32-.07-11,.09-2.21,0-4.5,0-6.76V66.45l0-4.58c0-2.32,0-4.64,0-6.94,0-1.78-.17-3.53-.25-5.3,0-.39,0-.77-.06-1.17,0-1.45.12-1.94.6-2.23.12-.06.23-.15.34-.19.37-.11.65.48.74,1.53.29,3.13.35,6.46.37,9.79v7.46Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M33.63,86.13l.1-2.6.15-2.6c0-.63,0-1.26,0-1.89.14-2.24.31-4.47.38-6.71,0-1,0-2-.07-3a10.71,10.71,0,0,1,.12-3.78c.11-.4.58-.38,1.14-.09a4.47,4.47,0,0,1,.91.64,1.67,1.67,0,0,1,.6,1,33.87,33.87,0,0,1,.52,3.85,31.9,31.9,0,0,1-.13,3.9,36,36,0,0,0,.15,4.75c0,1.75.06,3.5,0,5.25l0,3.23c0,1.63-.06,3.27,0,4.89.08,1.25.42,2.48.58,3.72a8.11,8.11,0,0,1,.12.82,1.52,1.52,0,0,1-.32,1.11,1.75,1.75,0,0,1-1,.49,4.34,4.34,0,0,1-.6.14,1.65,1.65,0,0,1-1.64-1,11.41,11.41,0,0,1-.86-3.35c-.15-1.14-.21-2.31-.26-3.48-.06-1.73,0-3.48,0-5.23Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M56,81.05l.08-3.42.14-3.42c0-.83,0-1.66,0-2.49.12-2.94.28-5.87.34-8.81,0-1.3,0-2.6-.06-3.89a21.76,21.76,0,0,1,.09-5c.09-.52.5-.48,1-.07a4.06,4.06,0,0,1,.81.87A2.54,2.54,0,0,1,59,56.13c.2,1.69.4,3.38.47,5.08s0,3.4-.12,5.11c-.15,2.05.09,4.17.12,6.26,0,2.29,0,4.59,0,6.89l-.05,4.24c0,2.15,0,4.3.05,6.42.07,1.65.37,3.27.52,4.9,0,.36.1.71.11,1.08a2.53,2.53,0,0,1-.28,1.44,1.48,1.48,0,0,1-.83.64,4.25,4.25,0,0,1-.53.19c-.58.13-1.1-.42-1.45-1.38a36.15,36.15,0,0,1-1-9c-.05-2.29,0-4.59,0-6.89Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M78.45,75.22l.09-4.47.15-4.48c0-1.08,0-2.17,0-3.26.13-3.83.29-7.66.36-11.5,0-1.7,0-3.4,0-5.09a38,38,0,0,1,.09-6.49c.09-.67.5-.62,1-.07A5.63,5.63,0,0,1,80.91,41a4.1,4.1,0,0,1,.53,1.68c.2,2.21.4,4.42.46,6.64s0,4.44-.13,6.68c-.15,2.67.08,5.44.11,8.18,0,3,0,6,0,9l-.05,5.54c0,2.8-.06,5.61,0,8.39.07,2.16.37,4.27.52,6.4,0,.47.09.93.11,1.41,0,1.76-.35,2.33-1.11,2.71a3.59,3.59,0,0,1-.53.25c-.58.17-1.1-.55-1.45-1.82a61.48,61.48,0,0,1-1-11.85c0-3,0-6,0-9Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M113.37,98.22a.59.59,0,0,0,.16-.08l.1-.08c.05,0,.05,0,0-.06l-.16-.08-.12-.06s-.32-.11-.49-.17c-.61-.19-1.23-.34-1.83-.56-2.1-.77-4.14-1.67-6.17-2.59l-2.73-1.18a9,9,0,0,1-3.3-2.1c-.3-.35.06-.53.56-.62a3.06,3.06,0,0,1,1.75.11c2.21.93,4.5,2,6.8,3.07a36.68,36.68,0,0,0,4.38,1.55l.9.28.45.14.25.07.39.1c.53.11,1,.26,1.55.35l1.59.27,0,.27-.3.42c-.21.28-.4.52-.6.77s-.49.59-.76.87l-.87.82c-.5.44-.86.72-1.3,1.08-1.29,1-2.62,1.94-3.87,2.93-1,.76-1.86,1.62-2.77,2.43-.2.18-.39.38-.59.55-.78.64-1.12.72-1.65.4a3.28,3.28,0,0,1-.37-.22c-.35-.29-.26-.84.24-1.42a32.47,32.47,0,0,1,5.13-4.56l2.06-1.52,1-.77.48-.39c.09-.06.05,0,.08,0Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M72.14,35A81.06,81.06,0,0,1,62,39.5c-1.27.44-2.51,1-3.78,1.38A102.21,102.21,0,0,1,44.49,44l-3.1.45c-1,.14-2.07.23-3.1.33-1.32.11-2.65.19-4,.2a18.71,18.71,0,0,1-4-.32c-.84-.2-.66-.32.05-.42.35,0,.84-.13,1.44-.24s1.27-.17,2-.22c1.32-.05,2.64-.26,4-.4l2-.29c.66-.08,1.32-.16,2-.28,2.63-.4,5.26-.91,7.88-1.47A68.88,68.88,0,0,0,59,38.42c1.67-.68,3.39-1.25,5-2.05s3.33-1.42,4.9-2.32l3-1.56c1-.49,1.9-1.15,2.85-1.72a73.78,73.78,0,0,0,8.24-5.84c1-.88,1.9-1.77,2.81-2.67l1.38-1.34c.46-.45.86-1,1.29-1.43s.73-.85,1.12-1.26c1.44-1.54,2-1.89,2.88-1.76a4.32,4.32,0,0,1,.56.1c.55.21.27,1.14-.71,2.4a39.79,39.79,0,0,1-4.85,5.42c-.91.83-1.84,1.66-2.77,2.49s-2,1.51-3,2.27L79.39,30.8c-.76.54-1.59,1-2.38,1.49-1.6,1-3.15,2-4.84,2.81Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M96.44,12.56l0-.14,0-.08c0-.05,0-.11,0-.18s-.08,0-.13,0a1.44,1.44,0,0,0-.29.11c-.48.27-1,.57-1.46.81A20.77,20.77,0,0,1,89,14.8c-.86.14-1.72.29-2.57.39a11.4,11.4,0,0,1-3.3.07c-.34,0-.29-.36,0-.7a2.31,2.31,0,0,1,1.38-.8c2.12-.29,4.17-.65,6.26-1.08a14.74,14.74,0,0,0,3.6-1.49l.74-.4,1.09-.62c.4-.22.78-.44,1.16-.63A11.33,11.33,0,0,1,98.44,9l-.13,1.79-.13,2-.11,1.39a26.59,26.59,0,0,1-.72,4.22,18.25,18.25,0,0,1-1,3.19,5.79,5.79,0,0,1-.31.67c-.46.81-.78.95-1.28.82-.11,0-.23-.06-.34-.11-.35-.17-.4-.65-.14-1.19a22.76,22.76,0,0,0,1.68-5.18c.12-.69.24-1.39.31-2.11,0-.35.07-.72.1-1.08l.06-.87Z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export const MagnifierIcon = () => {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 128 128"
|
||||
className="w-12 fill-primary"
|
||||
>
|
||||
<title>Free Icons</title>
|
||||
<g
|
||||
id="Layer_46"
|
||||
data-name="Layer 46"
|
||||
>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M60.58,28c1.89.06,3.8.09,5.7.09l2.08,0q3.66,0,7.34-.13c1.08,0,2.17-.11,3.25-.18,1.38-.05,2.76-.21,4.16-.14.43,0,.38,0,0,.16a8.62,8.62,0,0,1-1.81.48,68.81,68.81,0,0,1-8.5.56c-1.71,0-3.49.11-5.24.14-1.92,0-3.84,0-5.77,0l-3.55-.08c-1.79,0-3.59-.13-5.36-.22-1.39-.06-2.74-.08-4.11-.17l-.91-.05c-1.12-.14-1.46-.29-1.67-.57a1.77,1.77,0,0,1-.14-.16c-.09-.11.4-.32,1.22-.31,2.43.07,5,.27,7.54.39,1.91.09,3.83.17,5.74.2Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M58.21,28.25,55.88,28,55,28c-1-.11-2-.21-3-.35l-1.32-.13A7.5,7.5,0,0,1,49,27.23c-.19-.06-.1-.18.08-.29a1.25,1.25,0,0,1,.76-.22,26.71,26.71,0,0,1,3.44.27c.69.11,1.41.12,2.12.18l2.33.19,1.44.12c.73,0,1.46.1,2.18.12.56,0,1.12,0,1.67,0h.37c.45,0,.59.07.69.29a.94.94,0,0,1,.06.15c0,.17-.15.31-.49.36a14.62,14.62,0,0,1-3.11.07c-.78,0-1.56-.09-2.34-.15Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M55.41,88.66A15.53,15.53,0,0,0,61.2,95.9a18,18,0,0,0,3,1.69,17.28,17.28,0,0,0,12,1,17.58,17.58,0,0,0,5-2.22,23.83,23.83,0,0,0,5.14-4.73c.47-.55.77-.25.71.5a4.94,4.94,0,0,1-1.58,3,19.84,19.84,0,0,1-14.14,5.57,23.55,23.55,0,0,1-4.69-.61,20.07,20.07,0,0,1-4.42-1.72,18.08,18.08,0,0,1-7.41-7.12A16.32,16.32,0,0,1,53,85.22a18.1,18.1,0,0,1,1.46-9.39,20,20,0,0,1,4.09-6.07,15.5,15.5,0,0,1,1.19-1.1c1.59-1.28,2.26-1.45,2.83-1.31a1.7,1.7,0,0,1,.38.12c.33.22-.26.79-1.33,1.65a18.94,18.94,0,0,0-6.7,10.28,15.76,15.76,0,0,0,.57,9.24Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M51.72,117.14c1.84.13,3.69.22,5.53.28l2,0q3.56.14,7.13.18c1.06,0,2.12,0,3.16-.06a28.81,28.81,0,0,1,4,0c.42.07.37.3,0,.59a3,3,0,0,1-1.77.68,71.46,71.46,0,0,1-8.28,0c-1.66-.09-3.39,0-5.09,0-1.86,0-3.73-.1-5.6-.17l-3.45-.19c-1.74-.1-3.49-.25-5.22-.41-1.35-.12-2.68-.2-4-.42a5.74,5.74,0,0,1-.9-.18,2.54,2.54,0,0,1-1.15-.49.74.74,0,0,1-.31-.62,1.55,1.55,0,0,1,0-.31c.09-.31.61-.38,1.26-.19,2.16.42,4.62.65,7.08.88,1.83.15,3.69.3,5.54.39Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M23.72,104.17c-.23-.08-10,3-12.25,6.71s19,8,35,6.48L24,109.76Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M61.21,36.17c-4.82,1.74-12.35-1.35-14.67-2.75s-4.65-7.22-4.65-7.22l8.26.44S53.39,35.06,61.21,36.17Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M54.26,52.54A60.85,60.85,0,0,0,40.31,66.29a92.51,92.51,0,0,0-5.57,8.21,82.37,82.37,0,0,0-4.54,8.81,67.35,67.35,0,0,0-4.29,13.74c-.21,1-.35,2.09-.53,3.13s-.23,2.1-.35,3.15l-.17,3.16,0,1.59a4.59,4.59,0,0,0,0,.85L27.22,110c1,.47,2,.76,3,1.15,2,.8,4,1.3,6.08,1.94a126.74,126.74,0,0,0,25.38,3.83,143.43,143.43,0,0,0,22.81-.59,138.46,138.46,0,0,0,28.41-6.16c2.89-.89,2.67-.41.4.9-.57.33-1.27.71-2.08,1.13a20.66,20.66,0,0,1-2.77,1.27q-1.57.6-3.42,1.23c-.61.2-1.24.42-1.9.61l-2,.49a133.29,133.29,0,0,1-30,3.6,140.45,140.45,0,0,1-30.14-3l-4.45-1.08c-1.49-.38-3-.86-4.45-1.29s-2.93-1-4.41-1.55c-.74-.24-1.44-.61-2.17-.92l-2.72-1.23a4.91,4.91,0,0,1-.05-1l0-.87,0-1.18c0-.79,0-1.58.05-2.37,0-1.58.22-3.14.36-4.71A66.71,66.71,0,0,1,25,91.06a77,77,0,0,1,8.39-18.72,87.13,87.13,0,0,1,5.83-8.43A70.89,70.89,0,0,1,46,56.24a48.83,48.83,0,0,1,10.09-7.68,38.07,38.07,0,0,1,5.8-2.67,31.16,31.16,0,0,1,6.25-1.45,27.84,27.84,0,0,1,9.67.53,31.8,31.8,0,0,1,9,3.64,50.62,50.62,0,0,1,14,12.94,84.72,84.72,0,0,1,7.82,12.35,94.47,94.47,0,0,1,5.74,13.36c.68,2,1.33,4,1.84,6.14a41.26,41.26,0,0,1,1.38,8.43,8.82,8.82,0,0,1-.48,3.84,7.34,7.34,0,0,1-.48,1.12c-.59.72-.73-2.44-1.83-8A93.23,93.23,0,0,0,106,74.49a79.27,79.27,0,0,0-7-11.19,52.82,52.82,0,0,0-9.08-9.51c-5-4.06-11.12-6.87-17.5-7.06s-12.69,2.13-18,5.85Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M88.87,83c-.27,21-34.27,22.53-35.3,1.17A18.87,18.87,0,0,1,66.38,65.86C77.86,62.18,88.23,71.8,88.87,83c.07,1.28,2.07,1.29,2,0C90.2,71.23,80.23,61.16,68,63.42c-9.55,1.75-16.79,11.11-16.39,20.77,1,24,39,22.4,39.3-1.17A1,1,0,0,0,88.87,83Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M73.13,81.46c-.57.86-1.15,1.75-1.76,2.57-.22.3-.38.65-.6,1l-2.35,3.28c-.35.49-.61,1-.91,1.55a11.29,11.29,0,0,1-.57,1,4,4,0,0,1-.84.87c-.22.16-.46-.07-.67-.44a2.08,2.08,0,0,1-.34-1.36,13.57,13.57,0,0,1,2.33-4c.6-.74,1-1.64,1.57-2.45s1.26-1.75,1.93-2.57l1.22-1.55c.61-.78,1.24-1.56,1.8-2.36.44-.62.8-1.29,1.23-1.91.1-.14.18-.28.29-.42a1.12,1.12,0,0,1,.53-.44.66.66,0,0,1,.46,0,.85.85,0,0,1,.19.06c.18.09.17.4.06.86a36.13,36.13,0,0,1-1.9,3.71c-.53.91-1.09,1.8-1.63,2.71Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M72.51,45V41.46a1.38,1.38,0,0,0-2.75,0V45a1.38,1.38,0,0,0,2.75,0Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M78.21,38.25c-3.61.17-7.21.1-10.79,0-1.3,0-2.61,0-3.91-.08C59,38,54.16,37.77,49.7,36a17,17,0,0,1-2.84-1.47,13.76,13.76,0,0,1-2.45-2A15.52,15.52,0,0,1,42,29.22c-.65-1.17-1.09-2.42-1.68-3.49-.38-.61-.22-.74.46-.36a11.33,11.33,0,0,1,2.47,2.57c2.73,4.34,7,6.7,12.17,7.61a59.49,59.49,0,0,0,9.63.63c3.59.1,7.17.2,10.74.11,2.19,0,4.39-.15,6.57-.35a38.47,38.47,0,0,0,9.71-1.74,8.24,8.24,0,0,0,3.09-1.84,20.32,20.32,0,0,0,2.35-2.82l1-1.37C99.74,26.47,100.36,26,101,26a2.09,2.09,0,0,1,.44,0c.4.13,0,.9-.81,2.14a27.7,27.7,0,0,1-4.39,5.76,9.48,9.48,0,0,1-1.64,1.2c-.3.18-.62.32-.93.48s-.59.25-.89.35A25.44,25.44,0,0,1,89.13,37a52.14,52.14,0,0,1-5.46.81c-1.8.2-3.63.36-5.45.46Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M61.61,26.1q4.2.22,8.4.27c1,0,2-.05,3.06,0,3.61,0,7.21-.08,10.81-.25,1.6-.09,3.2-.25,4.77-.46,1-.07,2-.25,3-.36.5-.06,1-.12,1.51-.2s1-.07,1.53-.11.58,0,.09.31l-1,.61a6.6,6.6,0,0,1-1.54.57c-1,.22-2.06.49-3.1.67s-2.09.3-3.14.4c-2.1.2-4.21.35-6.33.36-2.53,0-5.15.2-7.74.23-2.84,0-5.69,0-8.53-.08l-5.24-.22c-2.65-.13-5.3-.33-7.93-.54-2-.15-4.06-.24-6.09-.47-.45-.06-.89-.09-1.34-.16l-.58-.1-.47-.16a5.7,5.7,0,0,1-.68-.31,2.09,2.09,0,0,1-.41-.32,2,2,0,0,1-.22-.4c-.05-.13-.13-.24-.15-.32-.09-.24.71-.6,1.88-.48,3.5.33,7.22.72,11,1,1.4.11,2.8.21,4.21.29s2.82.15,4.23.21Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M73.91,82.23a2.62,2.62,0,1,1-4.3-2A2.64,2.64,0,0,1,73.91,82.23Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M67.82,15.63c.15,0,0,.19-.2.51a1.45,1.45,0,0,1-.42.35,1.35,1.35,0,0,1-.34,0,5.47,5.47,0,0,1-.82-.62,1.87,1.87,0,0,1-.42-.56c-.21-.41-.42-.82-.58-1.22a.93.93,0,0,1-.05-.29,2,2,0,0,0-.22-.93c0-.05,0-.11-.11-.13a2.2,2.2,0,0,1-.38-.94c0-.28,0-.55,0-.83,0,0,0-.06,0-.12a.26.26,0,0,0,.09-.28,1.45,1.45,0,0,1,0-.36.76.76,0,0,1,.12-.24.65.65,0,0,1,.3-.15c.09,0,.17-.07.26-.12l.1,0a3.43,3.43,0,0,1,.86.49s.52.94.56,1,0,.12,0,.19.36.74.36.77.13.29,0,.49c0,0,0,.06,0,.09a4.25,4.25,0,0,1,.17.77,1.49,1.49,0,0,0,.14.37s0,0,0,.08,0,.07,0,.09a2.83,2.83,0,0,0,.39.8c0,.05.06.42.12.46S67.76,15.62,67.82,15.63Z"
|
||||
/>
|
||||
<path
|
||||
className="cls-1"
|
||||
d="M79.73,20.75c0,.15-.21.08-.56-.16a2.05,2.05,0,0,1-.42-.41c0-.11-.1-.22-.13-.3s.13-.53.15-.71a1.16,1.16,0,0,1,.19-.44c.17-.27.33-.57.5-.86a.43.43,0,0,1,.16-.17,1.33,1.33,0,0,0,.5-.63c0-.05,0-.08,0-.15s.34-.76.44-.81.44-.31.67-.45c0,0,0-.07.12-.05s.21,0,.27-.08a.73.73,0,0,1,.29-.19.9.9,0,0,1,.27,0,.87.87,0,0,1,.28.25c0,.09.15.15.24.23l.09.08a3,3,0,0,1,0,.78l-.17.37a3.3,3.3,0,0,0-.18.45c0,.05-.07.06-.12.09s-.23.64-.25.66-.1.26-.31.29c0,0,0,0-.06.06a2.22,2.22,0,0,1-.44.58,2.69,2.69,0,0,0-.19.32l-.07,0s-.06,0-.07.06a5.92,5.92,0,0,0-.51.76c0,.07-.39.24-.43.32S79.73,20.69,79.73,20.75Z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
@@ -1,129 +0,0 @@
|
||||
import { useState } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import {
|
||||
NavigationMenu,
|
||||
NavigationMenuItem,
|
||||
NavigationMenuList,
|
||||
} from "../components/ui/navigation-menu";
|
||||
import {
|
||||
Sheet,
|
||||
SheetContent,
|
||||
SheetHeader,
|
||||
SheetTitle,
|
||||
SheetTrigger,
|
||||
} from "../components/ui/sheet";
|
||||
|
||||
import { buttonVariants } from "./ui/button";
|
||||
import { Menu } from "lucide-react";
|
||||
import { ModeToggle } from "./mode-toggle";
|
||||
import { LogoIcon } from "./Icons";
|
||||
|
||||
interface RouteProps {
|
||||
href: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
const routeList: RouteProps[] = [
|
||||
{
|
||||
href: "#about",
|
||||
label: "About",
|
||||
},
|
||||
{
|
||||
href: "#howItWorks",
|
||||
label: "How it works",
|
||||
},
|
||||
{
|
||||
href: "#team",
|
||||
label: "Team",
|
||||
},
|
||||
{
|
||||
href: "#faq",
|
||||
label: "FAQ",
|
||||
},
|
||||
];
|
||||
|
||||
export const Navbar = () => {
|
||||
const [isOpen, setIsOpen] = useState<boolean>(false);
|
||||
return (
|
||||
<header className="sticky border-b-[1px] top-0 z-40 w-full bg-white dark:border-b-slate-700 dark:bg-background" style={{overflow: "hidden"}}>
|
||||
<NavigationMenu className="mx-auto">
|
||||
<NavigationMenuList className="container h-14 px-4 w-screen flex justify-between ">
|
||||
<NavigationMenuItem className="font-bold flex">
|
||||
<a href="#" className="ml-2 font-bold text-xl flex">
|
||||
<LogoIcon />
|
||||
SkillHub
|
||||
</a>
|
||||
</NavigationMenuItem>
|
||||
|
||||
{/* mobile */}
|
||||
<span className="flex md:hidden">
|
||||
<ModeToggle />
|
||||
|
||||
<Sheet open={isOpen} onOpenChange={setIsOpen}>
|
||||
<SheetTrigger className="px-2">
|
||||
<Menu
|
||||
className="flex md:hidden h-5 w-5"
|
||||
onClick={() => setIsOpen(true)}
|
||||
>
|
||||
<span className="sr-only">Menu Icon</span>
|
||||
</Menu>
|
||||
</SheetTrigger>
|
||||
|
||||
<SheetContent side={"left"}>
|
||||
<SheetHeader>
|
||||
<SheetTitle className="font-bold text-xl">
|
||||
SkillHub
|
||||
</SheetTitle>
|
||||
</SheetHeader>
|
||||
<nav className="flex flex-col justify-center items-center gap-2 mt-4">
|
||||
{routeList.map(({ href, label }: RouteProps) => (
|
||||
<a
|
||||
key={label}
|
||||
href={href}
|
||||
onClick={() => setIsOpen(false)}
|
||||
className={buttonVariants({ variant: "ghost" })}
|
||||
>
|
||||
{label}
|
||||
</a>
|
||||
))}
|
||||
<Link
|
||||
to={"login"}
|
||||
className={`w-[110px] border ${buttonVariants({
|
||||
variant: "default",
|
||||
})}`}
|
||||
>
|
||||
Login
|
||||
</Link>
|
||||
</nav>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
</span>
|
||||
|
||||
{/* desktop */}
|
||||
<nav className="hidden md:flex gap-2">
|
||||
{routeList.map((route: RouteProps, i) => (
|
||||
<a
|
||||
href={route.href}
|
||||
key={i}
|
||||
className={`text-[17px] ${buttonVariants({
|
||||
variant: "ghost",
|
||||
})}`}
|
||||
>
|
||||
{route.label}
|
||||
</a>
|
||||
))}
|
||||
</nav>
|
||||
|
||||
<div className="hidden md:flex gap-2">
|
||||
<Link
|
||||
to={"login"}
|
||||
className={`border ${buttonVariants({ variant: "default" })}`}
|
||||
>
|
||||
Signup
|
||||
</Link>
|
||||
</div>
|
||||
</NavigationMenuList>
|
||||
</NavigationMenu>
|
||||
</header>
|
||||
);
|
||||
};
|
||||
@@ -1,38 +0,0 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { Button } from "./ui/button";
|
||||
import { ArrowUpToLine } from "lucide-react";
|
||||
|
||||
export const ScrollToTop = () => {
|
||||
const [showTopBtn, setShowTopBtn] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener("scroll", () => {
|
||||
if (window.scrollY > 400) {
|
||||
setShowTopBtn(true);
|
||||
} else {
|
||||
setShowTopBtn(false);
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
|
||||
const goToTop = () => {
|
||||
window.scroll({
|
||||
top: 0,
|
||||
left: 0,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{showTopBtn && (
|
||||
<Button
|
||||
onClick={goToTop}
|
||||
className="fixed bottom-4 right-4 opacity-90 shadow-md"
|
||||
size="icon"
|
||||
>
|
||||
<ArrowUpToLine className="h-4 w-4" />
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1,76 +0,0 @@
|
||||
import { Card, CardDescription, CardHeader, CardTitle } from "./ui/card";
|
||||
import { MagnifierIcon, WalletIcon, ChartIcon } from "./Icons";
|
||||
import cubeLeg from "../assets/cube-leg.png";
|
||||
|
||||
interface ServiceProps {
|
||||
title: string;
|
||||
description: string;
|
||||
icon: JSX.Element;
|
||||
}
|
||||
|
||||
const serviceList: ServiceProps[] = [
|
||||
{
|
||||
title: "Code Collaboration",
|
||||
description:
|
||||
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Nisi nesciunt est nostrum omnis ab sapiente.",
|
||||
icon: <ChartIcon />,
|
||||
},
|
||||
{
|
||||
title: "Project Management",
|
||||
description:
|
||||
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Nisi nesciunt est nostrum omnis ab sapiente.",
|
||||
icon: <WalletIcon />,
|
||||
},
|
||||
{
|
||||
title: "Task Automation",
|
||||
description:
|
||||
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Nisi nesciunt est nostrum omnis ab sapiente.",
|
||||
icon: <MagnifierIcon />,
|
||||
},
|
||||
];
|
||||
|
||||
export const Services = () => {
|
||||
return (
|
||||
<section className="container py-24 sm:py-32">
|
||||
<div className="grid lg:grid-cols-[1fr,1fr] gap-8 place-items-center">
|
||||
<div>
|
||||
<h2 className="text-3xl md:text-4xl font-bold">
|
||||
<span className="bg-gradient-to-b from-primary/60 to-primary text-transparent bg-clip-text">
|
||||
Client-Centric{" "}
|
||||
</span>
|
||||
Services
|
||||
</h2>
|
||||
|
||||
<p className="text-muted-foreground text-xl mt-4 mb-8 ">
|
||||
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Veritatis
|
||||
dolor.
|
||||
</p>
|
||||
|
||||
<div className="flex flex-col gap-8">
|
||||
{serviceList.map(({ icon, title, description }: ServiceProps) => (
|
||||
<Card key={title}>
|
||||
<CardHeader className="space-y-1 flex md:flex-row justify-start items-start gap-4">
|
||||
<div className="mt-1 bg-primary/20 p-1 rounded-2xl">
|
||||
{icon}
|
||||
</div>
|
||||
<div>
|
||||
<CardTitle>{title}</CardTitle>
|
||||
<CardDescription className="text-md mt-2">
|
||||
{description}
|
||||
</CardDescription>
|
||||
</div>
|
||||
</CardHeader>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<img
|
||||
src={cubeLeg}
|
||||
className="w-[300px] md:w-[500px] lg:w-[600px] object-contain"
|
||||
alt="About services"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
@@ -1,137 +0,0 @@
|
||||
import { buttonVariants } from "../components/ui/button";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "../components/ui/card";
|
||||
import { Github } from "lucide-react";
|
||||
|
||||
interface TeamProps {
|
||||
imageUrl: string;
|
||||
name: string;
|
||||
position: string;
|
||||
socialNetworks: SociaNetworkslProps[];
|
||||
}
|
||||
|
||||
interface SociaNetworkslProps {
|
||||
name: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
const teamList: TeamProps[] = [
|
||||
{
|
||||
imageUrl: "https://raw.githubusercontent.com/devitq/devitq/main/logo.png",
|
||||
name: "ITQ",
|
||||
position: "Backend & Frontend Developer",
|
||||
socialNetworks: [
|
||||
{ name: "GitHub", url: "https://github.com/devitq" },
|
||||
],
|
||||
},
|
||||
{
|
||||
imageUrl: "https://cdn.discordapp.com/avatars/745800190413373472/db4cd19e6d80f9cfa29e09a43ddbcb28",
|
||||
name: "Pigeon",
|
||||
position: "Backend Developer",
|
||||
socialNetworks: [
|
||||
{ name: "GitHub", url: "https://github.com/FlyingPigeon-py" },
|
||||
],
|
||||
},
|
||||
{
|
||||
imageUrl: "https://cdn.discordapp.com/avatars/875043365815717888/2a6ddca40c178c5e91a55c52889f8a98",
|
||||
name: "Timkaoch",
|
||||
position: "Backend Developer",
|
||||
socialNetworks: [
|
||||
{ name: "GitHub", url: "https://github.com/Timur-liceist" },
|
||||
],
|
||||
},
|
||||
{
|
||||
imageUrl: "https://cdn.discordapp.com/avatars/743444918197944400/6dcfc04c3931fa5c89e9580eb5f7c655",
|
||||
name: "Data Name ID",
|
||||
position: "Backend Developer",
|
||||
socialNetworks: [
|
||||
{ name: "GitHub", url: "https://github.com/Data-Name-ID" },
|
||||
],
|
||||
},
|
||||
{
|
||||
imageUrl: "https://cdn.discordapp.com/avatars/545655609005965345/78d2c594eb858d3bb393928a67ef8731",
|
||||
name: "OMGKawaiiQueli!",
|
||||
position: "Frontend Developer",
|
||||
socialNetworks: [
|
||||
{ name: "GitHub", url: "https://github.com/cu-e" },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export const Team = () => {
|
||||
const socialIcon = (iconName: string) => {
|
||||
switch (iconName) {
|
||||
case "GitHub":
|
||||
return <Github size="20" />;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<section
|
||||
id="team"
|
||||
className="container py-24 sm:py-32"
|
||||
>
|
||||
<h2 className="text-3xl md:text-4xl font-bold">
|
||||
<span className="bg-gradient-to-b from-primary/60 to-primary text-transparent bg-clip-text">
|
||||
Our Dedicated{" "}
|
||||
</span>
|
||||
Crew
|
||||
</h2>
|
||||
|
||||
<p className="mt-4 mb-10 text-xl text-muted-foreground">
|
||||
Our team Animulichki contains 5 dedicated web developers
|
||||
</p>
|
||||
|
||||
<div className="grid md:grid-cols-2 lg:grid-cols-4 gap-8 gap-y-10">
|
||||
{teamList.map(
|
||||
({ imageUrl, name, position, socialNetworks }: TeamProps) => (
|
||||
<Card
|
||||
key={name}
|
||||
className="bg-muted/50 relative mt-8 flex flex-col justify-center items-center"
|
||||
>
|
||||
<CardHeader className="mt-8 flex justify-center items-center pb-2">
|
||||
<img
|
||||
src={imageUrl}
|
||||
alt={`${name} ${position}`}
|
||||
className="absolute -top-12 rounded-full w-24 h-24 aspect-square object-cover"
|
||||
/>
|
||||
<CardTitle className="text-center">{name}</CardTitle>
|
||||
<CardDescription className="text-primary">
|
||||
{position}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent className="text-center pb-2">
|
||||
<p></p>
|
||||
</CardContent>
|
||||
|
||||
<CardFooter>
|
||||
{socialNetworks.map(({ name, url }: SociaNetworkslProps) => (
|
||||
<div key={name}>
|
||||
<a
|
||||
href={url}
|
||||
target="_blank"
|
||||
className={buttonVariants({
|
||||
variant: "ghost",
|
||||
size: "sm",
|
||||
})}
|
||||
>
|
||||
<span className="sr-only">{name} icon</span>
|
||||
{socialIcon(name)}
|
||||
</a>
|
||||
</div>
|
||||
))}
|
||||
</CardFooter>
|
||||
</Card>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
@@ -1,40 +0,0 @@
|
||||
import React, { Component, RefObject } from "react";
|
||||
import OrgChart from "@balkangraph/orgchart.js";
|
||||
|
||||
interface Node {
|
||||
name: string;
|
||||
img: string;
|
||||
// Add more fields if needed
|
||||
}
|
||||
|
||||
interface ChartProps {
|
||||
nodes: Node[];
|
||||
}
|
||||
|
||||
export default class Chart extends Component<ChartProps> {
|
||||
private divRef: RefObject<HTMLDivElement>;
|
||||
private chart: any;
|
||||
|
||||
constructor(props: ChartProps) {
|
||||
super(props);
|
||||
this.divRef = React.createRef();
|
||||
}
|
||||
|
||||
shouldComponentUpdate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.chart = new OrgChart(this.divRef.current!, {
|
||||
nodes: this.props.nodes,
|
||||
nodeBinding: {
|
||||
field_0: "name",
|
||||
img_0: "img",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return <div id="tree" ref={this.divRef}></div>;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,6 @@
|
||||
// export const API_BASE = "https://animulichki.ru/api/"
|
||||
// export const API_BASE = "http://212.22.79.188/api/" //2 сервер
|
||||
export const API_BASE = "http://localhost/api/" //3 сервер
|
||||
|
||||
export const API_REG = "auth/signup/"
|
||||
export const API_CREATE_TOKEN = "auth/login/"
|
||||
export const API_EVENT = "events/"
|
||||
export const API_USERS = "users/"
|
||||
|
||||
// export const API_BASE = "http://158.160.56.239:8080/api/"
|
||||
// export const API_BASE = "http://212.22.79.188:9090/api/" //2 сервер
|
||||
export const API_BASE = "http://localhost:8080/api/" //3 сервер
|
||||
|
||||
export const API_REG = "registration/"
|
||||
export const API_CREATE_TOKEN = "token/"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { ThemeProvider } from "../../../theme-provider"
|
||||
import NavigationBar from "../../../widgets/NavigationBar/NavigationBar"
|
||||
import '../../../../i18n'
|
||||
import less from "./General.module.less"
|
||||
import Header from "../../../widgets/Header/Header"
|
||||
@@ -9,9 +10,12 @@ function General() {
|
||||
return (
|
||||
<ThemeProvider defaultTheme="system" storageKey="vite-ui-theme">
|
||||
<Header />
|
||||
<main className={less["main-content"]}>
|
||||
<div className={less['page-maket']}>
|
||||
<NavigationBar />
|
||||
<div className={less["main-content"]}>
|
||||
<Outlet/>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
|
||||
)
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
.card{
|
||||
max-width: 800px;
|
||||
padding: 20px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Card, CardHeader, CardTitle, CardContent } from "../../shared/ui/card"
|
||||
import less from "./PlayerCard.module.less";
|
||||
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "../../shared/ui/dialog";
|
||||
import { Separator } from "../../shared/ui/separator";
|
||||
|
||||
const PlayerCard = () =>{
|
||||
const { t } = useTranslation();
|
||||
|
||||
|
||||
return(
|
||||
<Card className={`${less["card"]} flex flex-row `}>
|
||||
<div className="flex flex-col">
|
||||
<CardHeader className="p-0">
|
||||
<CardTitle className="p-0">Lorem ipsum</CardTitle>
|
||||
</CardHeader >
|
||||
<CardContent className="p-0 mt-2">
|
||||
<p>{t("skills")}:</p>
|
||||
<p>{t("viewingProfile")}:</p>
|
||||
|
||||
</CardContent>
|
||||
<Dialog>
|
||||
<DialogTrigger className="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-9 px-4 py-1">{t("open")}</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>фио</DialogTitle>
|
||||
<DialogDescription>
|
||||
<Separator></Separator>
|
||||
такой то такой то
|
||||
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
)
|
||||
}
|
||||
export default PlayerCard;
|
||||
@@ -1,11 +1,12 @@
|
||||
.card-img{
|
||||
border: 2px solid #cdcdcd;
|
||||
border-radius: 8px;
|
||||
width: 30%;
|
||||
background: #d9d9d5
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #d9d9d9;
|
||||
}
|
||||
.card{
|
||||
max-width: 800px;
|
||||
width: 800px;
|
||||
padding: 20px;
|
||||
margin-bottom: 10px;
|
||||
height: 230px;
|
||||
}
|
||||
@@ -1,23 +1,18 @@
|
||||
import { Button } from "../../shared/ui/button";
|
||||
import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from "../../shared/ui/card"
|
||||
import less from "./TeamsCard.module.less";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const TeamsCard = () =>{
|
||||
const { t } = useTranslation();
|
||||
|
||||
return(
|
||||
<Card className={`${less["card"]} flex flex-row`}>
|
||||
<div className={less["card-img"]}></div>
|
||||
<div className="flex flex-col">
|
||||
<CardHeader className="p-0 pl-2">
|
||||
<CardHeader >
|
||||
<CardTitle>Lorem ipsum</CardTitle>
|
||||
<CardDescription>Lorem ipsum</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="p-0 pl-2 mt-4">
|
||||
<CardContent>
|
||||
<p>Lorem ipsum dolor sit amet consectetur. Lorem justo sit nunc commodo nam fames dui ac ullamcorper. Laoreet faucibus semper adipiscing lobortis.</p>
|
||||
</CardContent>
|
||||
<Button className="mt-5 ml-2">{t("respondRequest")}</Button>
|
||||
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
.card{
|
||||
max-width: 800px;
|
||||
padding: 20px;
|
||||
margin-bottom: 10px;
|
||||
|
||||
}
|
||||
.up{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.header{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content:space-between;
|
||||
padding: 0;
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Button } from "../../shared/ui/button";
|
||||
import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from "../../shared/ui/card"
|
||||
import less from "./VacancyCard.module.less";
|
||||
import { TrashIcon } from "lucide-react";
|
||||
import { deleteEvent } from "../../pages/AdminEventPage/AdminEventAPI";
|
||||
|
||||
interface VacancyCardProms{
|
||||
title: string;
|
||||
date: string;
|
||||
desc: string;
|
||||
cardId: string;
|
||||
admin: boolean;
|
||||
}
|
||||
|
||||
const VacancyCard = ({title, date, desc,cardId, admin = false} : VacancyCardProms) =>{
|
||||
const { t } = useTranslation();
|
||||
|
||||
|
||||
return(
|
||||
<Card className={`${less["card"]} flex flex-row `}>
|
||||
<div className="flex flex-col">
|
||||
<CardHeader className={less["header"]}>
|
||||
<div className={less["up"]}>
|
||||
<CardTitle className="p-0">{title}</CardTitle>
|
||||
<CardDescription>Дата начала: {date}</CardDescription>
|
||||
</div>
|
||||
{admin &&(
|
||||
<Button size="icon" variant="ghost" onClick={() => deleteEvent(cardId)}><TrashIcon/></Button>
|
||||
)}
|
||||
</CardHeader>
|
||||
<CardContent className="p-0 mt-4">
|
||||
<p>{desc}</p>
|
||||
</CardContent>
|
||||
<Button className="mt-2">{t("respondRequest")}</Button>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
)
|
||||
}
|
||||
export default VacancyCard;
|
||||
@@ -1,90 +0,0 @@
|
||||
import React, { useState } from "react";
|
||||
|
||||
export const CheckboxTree = ({ data, setGraph }) => {
|
||||
const [checkedItems, setCheckedItems] = useState({});
|
||||
|
||||
const handleCheckboxChange = (itemName, checked) => {
|
||||
setCheckedItems((prevCheckedItems) => {
|
||||
let newCheckedItems = { ...prevCheckedItems, [itemName]: checked };
|
||||
|
||||
if (checked) {
|
||||
const parts = itemName.split(".");
|
||||
parts.pop();
|
||||
let parent = parts.join(".");
|
||||
while (parent) {
|
||||
newCheckedItems = { ...newCheckedItems, [parent]: true };
|
||||
const parentParts = parent.split(".");
|
||||
parentParts.pop();
|
||||
parent = parentParts.join(".");
|
||||
}
|
||||
} else {
|
||||
uncheckChildren(itemName, newCheckedItems);
|
||||
}
|
||||
|
||||
setGraph(getGraph(newCheckedItems));
|
||||
|
||||
return newCheckedItems;
|
||||
});
|
||||
};
|
||||
|
||||
const getGraph = (checkedItems) => {
|
||||
const graph = {};
|
||||
|
||||
for (const itemName in checkedItems) {
|
||||
if (checkedItems[itemName]) {
|
||||
const parts = itemName.split(".");
|
||||
let currentNode = graph;
|
||||
|
||||
for (let i = 0; i < parts.length; i++) {
|
||||
const part = parts[i];
|
||||
if (!currentNode[part]) {
|
||||
currentNode[part] = {};
|
||||
}
|
||||
currentNode = currentNode[part];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return graph;
|
||||
};
|
||||
|
||||
const uncheckChildren = (parentName, checkedItems) => {
|
||||
for (const key in checkedItems) {
|
||||
if (key.startsWith(parentName + ".")) {
|
||||
checkedItems[key] = false;
|
||||
if (typeof checkedItems[key] === "object") {
|
||||
uncheckChildren(key, checkedItems);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const renderCheckboxes = (items, prefix = "") => {
|
||||
const renderedCheckboxes = [];
|
||||
for (const key in items) {
|
||||
const itemName = prefix ? `${prefix}.${key}` : key;
|
||||
renderedCheckboxes.push(
|
||||
<div key={itemName}>
|
||||
<input
|
||||
id={itemName}
|
||||
type="checkbox"
|
||||
checked={checkedItems[itemName] || false}
|
||||
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
||||
onChange={(e) => handleCheckboxChange(itemName, e.target.checked)}
|
||||
/>
|
||||
<label htmlFor={itemName}>{key}</label>
|
||||
</div>
|
||||
);
|
||||
if (typeof items[key] === "object") {
|
||||
renderedCheckboxes.push(
|
||||
<div key={`${itemName}-children`} style={{ paddingLeft: "20px" }}>
|
||||
{renderCheckboxes(items[key], itemName)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
return renderedCheckboxes;
|
||||
};
|
||||
|
||||
return <div>{renderCheckboxes(data)}</div>;
|
||||
};
|
||||
@@ -34,6 +34,6 @@
|
||||
}
|
||||
.p{
|
||||
font-size: 16px;
|
||||
color: #595959;
|
||||
color: #d3d3d3;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,8 +32,7 @@ const UserProfile = () => {
|
||||
<Card className={less.card}>
|
||||
<h1 className={less.h1}>Имя Фамилия</h1>
|
||||
<Separator />
|
||||
<p>wefqwf</p>
|
||||
<p className={less.p}>Lorem ipsum dolor sit amet consectetur. Lorem justo sit nunc commodo nam fames dui ac ullamcorper. Laoreet faucibus semper adipiscing lobortis.</p>
|
||||
<p className={less.p}></p>
|
||||
|
||||
</Card>
|
||||
</section>
|
||||
|
||||
@@ -1,40 +1,41 @@
|
||||
import { Button } from "../components/ui/button";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "../components/ui/dropdown-menu";
|
||||
import { useTheme } from "../components/theme-provider";
|
||||
import { Moon, Sun } from "lucide-react";
|
||||
import { Moon, Sun } from "lucide-react"
|
||||
|
||||
import { Button } from "./shared/ui/button"
|
||||
import { useTheme } from "./theme-provider"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { MenubarMenu, MenubarTrigger, MenubarContent, MenubarItem, MenubarSeparator, MenubarShortcut } from "./shared/ui/menubar"
|
||||
import { ResetIcon } from "@radix-ui/react-icons"
|
||||
|
||||
|
||||
|
||||
export function ModeToggle() {
|
||||
const { setTheme } = useTheme();
|
||||
const { setTheme } = useTheme()
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="ghost"
|
||||
>
|
||||
<Sun className="h-[1.1rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
|
||||
<Moon className="absolute h-[1.1rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
|
||||
<MenubarMenu>
|
||||
<MenubarTrigger asChild>
|
||||
<Button variant="ghost" size="sm">
|
||||
<Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
|
||||
<Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
|
||||
<span className="sr-only">Toggle theme</span>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem onClick={() => setTheme("light")}>
|
||||
Light
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => setTheme("dark")}>
|
||||
Dark
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => setTheme("system")}>
|
||||
System
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
</MenubarTrigger>
|
||||
<MenubarContent align="end">
|
||||
<MenubarItem onClick={() => setTheme("light")}>
|
||||
{t("LightTheme")}<MenubarShortcut>⌘L</MenubarShortcut>
|
||||
</MenubarItem>
|
||||
<MenubarItem onClick={() => setTheme("dark")}>
|
||||
{t("DarkTheme")}<MenubarShortcut>⌘D</MenubarShortcut>
|
||||
</MenubarItem>
|
||||
<MenubarSeparator />
|
||||
<MenubarItem onClick={() => setTheme("system")}>
|
||||
{t("SystemTheme")}<MenubarShortcut><ResetIcon /></MenubarShortcut>
|
||||
</MenubarItem>
|
||||
</MenubarContent>
|
||||
</MenubarMenu>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
.main-admin{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 80%;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 50px;
|
||||
height: 70vh;
|
||||
}
|
||||
.full-content{
|
||||
padding-top: 80px;
|
||||
|
||||
}
|
||||
.card{
|
||||
max-width: 800px;
|
||||
padding: 20px;
|
||||
margin-bottom: 10px;
|
||||
margin-left: 5px;
|
||||
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
import {
|
||||
ResizableHandle,
|
||||
ResizablePanel,
|
||||
ResizablePanelGroup,
|
||||
} from "../../shared/ui/resizable";
|
||||
import less from "./Admin.module.less";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import CreateTeam from "../../widgets/CreateTeams/CreateTeams";
|
||||
import { UserList } from "../AdminEventPage/AdminEventAPI";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from "../../shared/ui/card"
|
||||
|
||||
|
||||
const AdminPage = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
|
||||
const [players, setPlayerList] = useState<Event[]>([]);
|
||||
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
var index = window.location.pathname.indexOf("/dash/admin/") + "/dash/admin/".length;
|
||||
|
||||
var result = window.location.pathname.substring(index);
|
||||
if(Number(result) > 0){
|
||||
UserList(result)
|
||||
.then((data) => {
|
||||
setPlayerList(data);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Возникла ошибка с получением:", error);
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
return (
|
||||
<ResizablePanelGroup className={less["full-content"]} direction="horizontal">
|
||||
<ResizablePanel defaultSize={60} maxSize={60}>
|
||||
<div className={less["main-admin"]}>
|
||||
<CreateTeam />
|
||||
</div>
|
||||
</ResizablePanel>
|
||||
<ResizableHandle withHandle />
|
||||
<ResizablePanel>
|
||||
<h4>Members: {players.length}</h4>
|
||||
{players.map((event) => (
|
||||
<Card className={`${less["card"]} flex flex-row `}>
|
||||
<div className="flex flex-col">
|
||||
<CardHeader className="p-0">
|
||||
<CardTitle className="p-0">{`${event.first_name} | ${event.email}`}</CardTitle>
|
||||
</CardHeader >
|
||||
<CardContent className="p-0 mt-2">
|
||||
<p>{t("skills")}:</p>
|
||||
<p>{event.bio}</p>
|
||||
|
||||
</CardContent>
|
||||
</div>
|
||||
</Card>
|
||||
))}
|
||||
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
);
|
||||
};
|
||||
export default AdminPage;
|
||||
@@ -1,108 +0,0 @@
|
||||
import { FormEvent } from "react";
|
||||
import { API_BASE, API_EVENT, API_USERS } from "../../app/APIurl";
|
||||
|
||||
export const submitAddEvent = (e: FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
const formData = new FormData(e.currentTarget);
|
||||
const formProps = Object.fromEntries(formData);
|
||||
console.log(formProps)
|
||||
|
||||
|
||||
fetch(`${API_BASE}${API_EVENT}`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(formProps) ,
|
||||
})
|
||||
.then(response => {
|
||||
|
||||
console.log(response.status);
|
||||
|
||||
if (response.ok) {
|
||||
console.log('Создан:', response.headers.get('Location'));
|
||||
return response.json();
|
||||
} else {
|
||||
|
||||
throw new Error('Код ошибки: ' + response.status);
|
||||
}
|
||||
})
|
||||
.then(data => {
|
||||
console.log('Успешно:', data);
|
||||
return data
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Возникла ошибка с созданием:', error);
|
||||
});
|
||||
}
|
||||
export const eventList = () => {
|
||||
return fetch(`${API_BASE}${API_EVENT}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
return response.json();
|
||||
} else {
|
||||
throw new Error('Код ошибки: ' + response.status);
|
||||
}
|
||||
})
|
||||
.then(data => {
|
||||
return data;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Возникла ошибка с получением:', error);
|
||||
});
|
||||
}
|
||||
|
||||
//удалить ивент
|
||||
export const deleteEvent = (id:string) => {
|
||||
fetch(`${API_BASE}${API_EVENT}${id}`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
|
||||
} else {
|
||||
throw new Error('Код ошибки: ' + response.status);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Возникла ошибка с удалением:', error);
|
||||
});
|
||||
}
|
||||
|
||||
//получение списка юзеров
|
||||
export const UserList = (id:string) => {
|
||||
|
||||
return fetch(`${API_BASE}${API_EVENT}${id}/${API_USERS}`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
})
|
||||
.then(response => {
|
||||
|
||||
console.log(response.status);
|
||||
|
||||
if (response.ok) {
|
||||
console.log('Получил:', response.headers.get('Location'));
|
||||
return response.json();
|
||||
} else {
|
||||
|
||||
throw new Error('Код ошибки: ' + response.status);
|
||||
}
|
||||
})
|
||||
.then(data => {
|
||||
console.log('Успешно:', data);
|
||||
return data
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Возникла ошибка с получением:', error);
|
||||
});
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
.main-admin{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 80%;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 50px;
|
||||
margin-top: 40px;
|
||||
height: 70vh;
|
||||
}
|
||||
.admin-event__page{
|
||||
display: flex;
|
||||
}
|
||||
.cont_1{
|
||||
width: 50%;
|
||||
border-right-width: 1px;
|
||||
height: 100vh;
|
||||
padding: 20px;
|
||||
|
||||
}
|
||||
.cont_2{
|
||||
width: 50%;
|
||||
padding: 20px;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.input-form{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
}
|
||||
.liner-block{
|
||||
display: flex;
|
||||
|
||||
align-items: center;
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
import { Input } from "../../shared/ui/input";
|
||||
import VacancyCard from "../../entities/VacancyCard/VacancyCard";
|
||||
import less from "./AdminEventPage.module.less"
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Button } from "../../shared/ui/button";
|
||||
import { Textarea } from "../../shared/ui/textarea";
|
||||
import { eventList, submitAddEvent } from "./AdminEventAPI";
|
||||
import { Switch } from "../../shared/ui/switch";
|
||||
import { Label } from "../../shared/ui/label";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
|
||||
|
||||
const AdminEventPage = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
|
||||
const [events, setEvents] = useState<Event[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
eventList().then((data) => {
|
||||
setEvents(data)
|
||||
}).catch(error => {
|
||||
console.error('Возникла ошибка с получением:', error)
|
||||
})
|
||||
}, []);
|
||||
|
||||
|
||||
return (
|
||||
<div className={less["admin-event__page"]}>
|
||||
<div className={less["cont_1"]}>
|
||||
<form className={less["input-form"]} onSubmit={(event) => submitAddEvent(event)}>
|
||||
<h1 className={less["title-titleform"]}>{t("createEvent")}</h1>
|
||||
<Input type="text" name="title" placeholder="Event name" />
|
||||
<Input type="date" name="start_date" placeholder="Start Date" />
|
||||
<Input type="date" name="end_date" placeholder="End Date" />
|
||||
|
||||
<Textarea name="description" placeholder="About Event" />
|
||||
<div className={less["liner-block"]}>
|
||||
<Switch name="is_online" />
|
||||
<Label htmlFor="airplane-mode">Онлайн мероприятие</Label>
|
||||
</div>
|
||||
<Button>{t("createEvent")}</Button>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
<div className={less["cont_2"]}>
|
||||
{events.map((event) => (
|
||||
<VacancyCard title={event.title} date={event.start_date} desc={event.description} cardId={event.id} admin={true}></VacancyCard>
|
||||
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default AdminEventPage
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
font-family: "Arial Black";
|
||||
margin-top: 200px;
|
||||
margin-left: 20px;
|
||||
font-size: 120px;
|
||||
font-size: 150px;
|
||||
line-height: 100%;
|
||||
text-transform: uppercase;
|
||||
|
||||
@@ -21,67 +21,6 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 500px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.desc-text{
|
||||
margin-top: 10px;
|
||||
margin-bottom: 2px;
|
||||
text-align: center;
|
||||
word-wrap: break-word;
|
||||
|
||||
}
|
||||
@media (max-width: 910px) {
|
||||
.landing{
|
||||
font-family: "Arial Black";
|
||||
margin-top: 100px;
|
||||
margin-left: 20px;
|
||||
font-size: 100px;
|
||||
line-height: 100%;
|
||||
text-transform: uppercase;
|
||||
|
||||
}
|
||||
}
|
||||
@media (max-width: 760px) {
|
||||
.landing{
|
||||
font-family: "Arial Black";
|
||||
margin-top: 100px;
|
||||
margin-left: 20px;
|
||||
font-size: 80px;
|
||||
line-height: 100%;
|
||||
text-transform: uppercase;
|
||||
|
||||
}
|
||||
}
|
||||
@media (max-width: 520px) {
|
||||
.landing{
|
||||
font-family: "Arial Black";
|
||||
margin-top: 100px;
|
||||
margin-left: 20px;
|
||||
font-size: 60px;
|
||||
line-height: 100%;
|
||||
text-transform: uppercase;
|
||||
|
||||
}
|
||||
.info-block{
|
||||
display: flex;
|
||||
position:absolute;
|
||||
bottom: 0px;
|
||||
padding: 5px;
|
||||
padding-bottom: 15px;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin: 0 auto;
|
||||
background-color: rgba(88, 88, 88, 0.4);
|
||||
}
|
||||
}
|
||||
@media (max-width: 400px) {
|
||||
.landing{
|
||||
font-family: "Arial Black";
|
||||
margin-top: 100px;
|
||||
margin-left: 20px;
|
||||
font-size: 40px;
|
||||
line-height: 100%;
|
||||
text-transform: uppercase;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,27 +1,21 @@
|
||||
import { About } from "../../About";
|
||||
import { FAQ } from "../../FAQ";
|
||||
import { Footer } from "../../Footer";
|
||||
import { Hero } from "../../Hero";
|
||||
import { HowItWorks } from "../../HowItWorks";
|
||||
import { Navbar } from "../../Navbar";
|
||||
import { ScrollToTop } from "../../ScrollToTop";
|
||||
import { Team } from "../../Team";
|
||||
import "../../../App.css";
|
||||
import { ThemeProvider } from "../../theme-provider.tsx";
|
||||
import less from "./Landing.module.less"
|
||||
import '../../../i18n'
|
||||
import { Button } from "../../shared/ui/button"
|
||||
import { Label } from "@radix-ui/react-menubar"
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
function Landing() {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<ThemeProvider>
|
||||
<Navbar />
|
||||
<Hero />
|
||||
<About />
|
||||
<HowItWorks />
|
||||
<Team />
|
||||
<FAQ />
|
||||
<Footer />
|
||||
<ScrollToTop />
|
||||
</ThemeProvider>
|
||||
);
|
||||
<><div className={less.block}></div>
|
||||
<h1 className={less.landing}>{t("landingLogo")}</h1>
|
||||
<div className={less["info-block"]}>
|
||||
<Label className="mt-10 mb-1">Lorem ipsum dolor sit amet consectetur. Tincidunt nunc duis interdum feugiat viverra tellus eu amet fermentum. Metus nulla lacinia egestas scelerisque porta urna et massa. Id ut vel aliquet lorem velit. Blandit interdum enim suspendisse non at sem nulla diam ullamcorper.</Label>
|
||||
<Button variant="outline">{t("buttonGoTOReg")}</Button>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default Landing;
|
||||
export default Landing
|
||||
@@ -1,66 +1,6 @@
|
||||
.divv{
|
||||
margin: 0;
|
||||
}
|
||||
.novis{
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
.general-content{
|
||||
margin-left: 20px;
|
||||
display: flex;
|
||||
}
|
||||
.general-left{
|
||||
width: 50%;
|
||||
padding: 10px;
|
||||
padding-top: 80px;
|
||||
border-right-width: 1px;
|
||||
}
|
||||
.general-right{
|
||||
padding-top: 80px;
|
||||
margin-left: 20px;
|
||||
width: 30%;
|
||||
|
||||
}
|
||||
.input-form{
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
width: 80%;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
.input-item{
|
||||
width: 80%;
|
||||
}
|
||||
.title-form{
|
||||
font-size: 30px;
|
||||
}
|
||||
.card{
|
||||
max-width: 800px;
|
||||
padding: 20px;
|
||||
margin-bottom: 10px;
|
||||
|
||||
}
|
||||
.up{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.header{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content:space-between;
|
||||
padding: 0;
|
||||
}
|
||||
.model-content{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content:center;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@media (max-width: 820px) {
|
||||
.general-left{
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,124 +1,14 @@
|
||||
import less from "./Main.module.less";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Input } from "../../shared/ui/input";
|
||||
import { submitRegister } from "../../widgets/Header/AuthAPI";
|
||||
import { Button } from "../../shared/ui/button";
|
||||
import { Textarea } from "../../shared/ui/textarea";
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
import { useEffect, useState } from "react";
|
||||
import { deleteEvent, eventList } from "../AdminEventPage/AdminEventAPI";
|
||||
import { CheckboxTree } from "../../features/Skills/Skills";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "../../ui/card";
|
||||
import { TrashIcon } from "lucide-react";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "../../shared/ui/dialog";
|
||||
import SearchBar from "../../features/SearchBar/SearchBar";
|
||||
import TeamsCard from "../../entities/TeamsCard/TeamsCard";
|
||||
import less from "./Main.module.less"
|
||||
|
||||
|
||||
const Main = () => {
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [graph, setGraph] = useState({});
|
||||
const [events, setEvents] = useState<Event[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
eventList()
|
||||
.then((data) => {
|
||||
setEvents(data);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Возникла ошибка с получением:", error);
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className={less["general-content"]}>
|
||||
<div className={less["general-left"]}>
|
||||
{events.map((event) => (
|
||||
<Card className={`${less["card"]} flex flex-row `}>
|
||||
<div className="flex flex-col">
|
||||
<CardHeader className={less["header"]}>
|
||||
<div className={less["up"]}>
|
||||
<CardTitle className="p-0">{event.title}</CardTitle>
|
||||
<CardDescription>
|
||||
Start Date: {event.start_date}
|
||||
</CardDescription>
|
||||
</div>
|
||||
{false && (
|
||||
<Button
|
||||
size="icon"
|
||||
variant="ghost"
|
||||
onClick={() => deleteEvent(event.id)}
|
||||
>
|
||||
<TrashIcon />
|
||||
</Button>
|
||||
)}
|
||||
</CardHeader>
|
||||
<CardContent className="p-0 mt-4">
|
||||
<p>{event.description}</p>
|
||||
</CardContent>
|
||||
<Dialog style={{ height: "fixed" }}>
|
||||
<DialogTrigger className="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground hover:bg-primary/90 h-9 px-4 py-2">
|
||||
{t("respondRequest")}
|
||||
</DialogTrigger>
|
||||
<DialogContent className={"lg:max-w-screen-lg overflow-y-scroll max-h-screen"}>
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
<h1 className={less["title-form"]}>{t("entrance")}</h1>
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
<form
|
||||
className={less["input-form"]}
|
||||
onSubmit={(event) => submitRegister(event, navigate, graph)}
|
||||
>
|
||||
<div className={less["novis"]}>
|
||||
<Input
|
||||
type="text"
|
||||
name="event"
|
||||
value={event.id}
|
||||
placeholder="Event"
|
||||
/>
|
||||
</div>
|
||||
<Input
|
||||
type="text"
|
||||
name="first_name"
|
||||
placeholder="First name"
|
||||
/>
|
||||
<Input
|
||||
type="text"
|
||||
name="last_name"
|
||||
placeholder="Last name"
|
||||
/>
|
||||
<Input type="date" name="birth_date" placeholder="Date" />
|
||||
<Input type="email" name="email" placeholder="Email" />
|
||||
<Textarea name="bio" placeholder="About" />
|
||||
<CheckboxTree data={event.tree} setGraph={setGraph} />
|
||||
|
||||
<Button>Signup</Button>
|
||||
</form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
</Card>
|
||||
))}
|
||||
<Button variant="link" asChild>
|
||||
<Link to={"/dash/skill-tree"}>{t("iorganizer")}</Link>
|
||||
</Button>
|
||||
</div>
|
||||
<div className={less["general-right"] + " shadow"}></div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Main;
|
||||
return (
|
||||
<><div><SearchBar title="Вакансии" />
|
||||
</div><div className={less["general-content"]}>
|
||||
<TeamsCard />
|
||||
</div></>
|
||||
)
|
||||
}
|
||||
export default Main;
|
||||
@@ -1,7 +1,7 @@
|
||||
import TeamCard from "../../widgets/TeamInfoBlock/TeamInfoBlock";
|
||||
import TeamCard from "../../widgets/TeamCard/TeamCard";
|
||||
import UserProfile from "../../features/UserProfile/UserProfile";
|
||||
import less from "./MyTeams.module.less"
|
||||
import CreateTeam from "../../widgets/CreateTeams/CreateTeams";
|
||||
import CreateTeam from "../../widgets/CreateTeam/CreateTeam";
|
||||
|
||||
|
||||
const MyTeams = () => {
|
||||
|
||||