Compare commits
76 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 393109a135 | |||
| 37a88865b6 | |||
| f075af9aa1 | |||
| 08dd7b7e55 | |||
| 1d5959e08d | |||
| 2e499f02a9 | |||
| a6d2dbdc16 | |||
| b8ac78f346 | |||
| b049071ded | |||
| aedde01192 | |||
| 6ad542f934 | |||
| 5214e03bfc | |||
| 7bc286d9d5 | |||
| 18161c9227 | |||
| f1b1e3388a | |||
| bf6add250a | |||
| 5d4340ae28 | |||
| d3efab753f | |||
| 4d6997457b | |||
| 635dfcd114 | |||
| 0eda4df17a | |||
| 34a1494512 | |||
| f46e92b32a | |||
| bee2e66cb4 | |||
| 5d6ad08f8b | |||
| f989a0c041 | |||
| 1764490d74 | |||
| 0165f95965 | |||
| 0bbc99c927 | |||
| 41b9d2ff8b | |||
| ce06c78a89 | |||
| 2f8fcdcc93 | |||
| 1ef976bfc6 | |||
| 2e2c71e09e | |||
| 5466d7ecba | |||
| adb0767f31 | |||
| 50a4a5eb58 | |||
| 2c7db1bf2a | |||
| 37b8f24849 | |||
| 871654e8fd | |||
| 162e492f93 | |||
| 747e199b84 | |||
| 802c28ebb6 | |||
| 852eacdcb5 | |||
| 53ca9317a0 | |||
| d0523ba3a9 | |||
| 050fe72547 | |||
| e1f438909c | |||
| 8d6323a364 | |||
| 88b93f7321 | |||
| 1b54e1e238 | |||
| e5faea0df4 | |||
| 4c6a5ff723 | |||
| 196044bdac | |||
| 4bfa151c96 | |||
| ded4dc468f | |||
| b7590630ca | |||
| 0d34a550d6 | |||
| 8aff38bd01 | |||
| a54df648c3 | |||
| 58ce699984 | |||
| 13b5bc679c | |||
| 64015fa383 | |||
| 4ab1eeeb26 | |||
| 96077981a2 | |||
| dd563715f2 | |||
| cb40fb71c8 | |||
| 6958e3934a | |||
| bdcc7eba4e | |||
| 95f04afd68 | |||
| 92d2288bcc | |||
| 07dd23ee8e | |||
| de951ae100 | |||
| 630e8e2114 | |||
| 9f233eb163 | |||
| 52233d0028 |
@@ -34,6 +34,7 @@ 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,2 +1 @@
|
||||
pyproject.toml
|
||||
poetry.lock
|
||||
.DS_Store
|
||||
|
||||
@@ -1,3 +1 @@
|
||||
# Folders
|
||||
venv/
|
||||
__pycache__/
|
||||
Dockerfile
|
||||
|
||||
@@ -1 +1 @@
|
||||
# SkillHub Backend folder
|
||||
# SkillHub Backend
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
from django.db import models
|
||||
|
||||
|
||||
class AbstractTag(models.Model):
|
||||
name = models.CharField(
|
||||
max_length=255,
|
||||
unique=True,
|
||||
)
|
||||
class BaseModel(models.Model):
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class TeamsConfig(AppConfig):
|
||||
class EventsConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "api.teams"
|
||||
name = "api.events"
|
||||
@@ -0,0 +1,35 @@
|
||||
# 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,
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,59 @@
|
||||
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
|
||||
@@ -0,0 +1,9 @@
|
||||
from rest_framework import serializers
|
||||
|
||||
from api.events.models import Event
|
||||
|
||||
|
||||
class EventSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Event
|
||||
fields = "__all__"
|
||||
@@ -0,0 +1,19 @@
|
||||
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",
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,80 @@
|
||||
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
|
||||
@@ -0,0 +1,44 @@
|
||||
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)
|
||||
@@ -1,32 +0,0 @@
|
||||
from django.contrib import admin
|
||||
|
||||
from api.notifications import models
|
||||
from api.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)
|
||||
@@ -1,6 +0,0 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class NotificationsConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "api.notifications"
|
||||
@@ -1,23 +0,0 @@
|
||||
from django import forms
|
||||
|
||||
from api.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,
|
||||
)
|
||||
@@ -1,24 +0,0 @@
|
||||
# Generated by Django 5.0.3 on 2024-04-01 14:59
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Notification',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('title', models.CharField(max_length=150)),
|
||||
('content', models.TextField(verbose_name='content')),
|
||||
('read', models.BooleanField(default=False)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -1,23 +0,0 @@
|
||||
# Generated by Django 5.0.3 on 2024-04-01 14:59
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('notifications', '0001_initial'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='notification',
|
||||
name='user',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='notifications', to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
]
|
||||
@@ -1,36 +0,0 @@
|
||||
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
|
||||
@@ -1,8 +0,0 @@
|
||||
from notifications.models import Notification
|
||||
from rest_framework import serializers
|
||||
|
||||
|
||||
class NotificationSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Notification
|
||||
fields = ["title", "content", "read", "created_at"]
|
||||
@@ -1,13 +0,0 @@
|
||||
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 +0,0 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class PingConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "api.ping"
|
||||
@@ -1,7 +0,0 @@
|
||||
from django.urls import path
|
||||
|
||||
import api.ping.views
|
||||
|
||||
urlpatterns = [
|
||||
path("", api.ping.views.PingApiView.as_view(), name="ping"),
|
||||
]
|
||||
@@ -1,9 +0,0 @@
|
||||
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)
|
||||
@@ -1,36 +0,0 @@
|
||||
# Generated by Django 5.0.3 on 2024-04-01 14:59
|
||||
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Team',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('description', models.TextField()),
|
||||
('avatar', models.ImageField(blank=True, upload_to='teams_avatars')),
|
||||
('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='город')),
|
||||
],
|
||||
),
|
||||
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)),
|
||||
('start_date', models.DateField(blank=True, null=True)),
|
||||
('end_date', models.DateField(blank=True, null=True)),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -1,49 +0,0 @@
|
||||
# Generated by Django 5.0.3 on 2024-04-01 14:59
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('teams', '0001_initial'),
|
||||
('users', '0001_initial'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='team',
|
||||
name='author',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='teams', to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='team',
|
||||
name='members',
|
||||
field=models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='vacancy',
|
||||
name='skills',
|
||||
field=models.ManyToManyField(blank=True, related_name='vacancies', to='users.skill'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='vacancy',
|
||||
name='specialization',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='users.specialization'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='vacancy',
|
||||
name='users',
|
||||
field=models.ManyToManyField(blank=True, related_name='vacancies', to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='team',
|
||||
name='vacancies',
|
||||
field=models.ManyToManyField(blank=True, to='teams.vacancy'),
|
||||
),
|
||||
]
|
||||
@@ -1,85 +0,0 @@
|
||||
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,
|
||||
)
|
||||
start_date = models.DateField(
|
||||
blank=True,
|
||||
null=True,
|
||||
)
|
||||
end_date = models.DateField(
|
||||
blank=True,
|
||||
null=True,
|
||||
)
|
||||
specialization = models.ForeignKey(
|
||||
Specialization,
|
||||
on_delete=models.CASCADE,
|
||||
blank=True,
|
||||
null=True,
|
||||
)
|
||||
skills = models.ManyToManyField(
|
||||
Skill,
|
||||
blank=True,
|
||||
related_name="vacancies",
|
||||
)
|
||||
users = models.ManyToManyField(
|
||||
User,
|
||||
blank=True,
|
||||
related_name="vacancies",
|
||||
)
|
||||
|
||||
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,
|
||||
)
|
||||
|
||||
vacancies = models.ManyToManyField(
|
||||
Vacancy,
|
||||
blank=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, related_name="teams"
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
@@ -1,33 +0,0 @@
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
from rest_framework import serializers
|
||||
|
||||
from api.teams.models import Team, Vacancy
|
||||
|
||||
|
||||
class TeamSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Team
|
||||
fields = ["id", "name", "description"]
|
||||
|
||||
|
||||
class VacancySerializer(serializers.ModelSerializer):
|
||||
min_age = serializers.IntegerField(write_only=True, required=True)
|
||||
max_age = serializers.IntegerField(write_only=True, required=True)
|
||||
|
||||
class Meta:
|
||||
model = Vacancy
|
||||
fields = "__all__"
|
||||
|
||||
def create(self, validated_data):
|
||||
min_age = validated_data.pop("min_age")
|
||||
max_age = validated_data.pop("max_age")
|
||||
|
||||
validated_data["start_date"] = datetime.now(
|
||||
timezone.utc
|
||||
).date() - timedelta(days=365 * min_age)
|
||||
validated_data["end_date"] = datetime.now(
|
||||
timezone.utc
|
||||
).date() - timedelta(days=365 * max_age)
|
||||
|
||||
return Team.objects.create(**validated_data)
|
||||
@@ -1,16 +0,0 @@
|
||||
from django.urls import path
|
||||
|
||||
from .views import AddUserToTeam, CreateVacancy
|
||||
|
||||
urlpatterns = [
|
||||
path(
|
||||
"add_user_to_team/<int:team_id>/<int:user_id>/",
|
||||
AddUserToTeam.as_view(),
|
||||
name="add_user_to_team",
|
||||
),
|
||||
path(
|
||||
"create_vacancy/",
|
||||
CreateVacancy.as_view(),
|
||||
name="create_vacancy",
|
||||
),
|
||||
]
|
||||
@@ -1,32 +0,0 @@
|
||||
from rest_framework import status
|
||||
from rest_framework.generics import CreateAPIView
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from api.teams.models import Team
|
||||
from api.teams.serializers import TeamSerializer, VacancySerializer
|
||||
from api.users.models import User
|
||||
|
||||
|
||||
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)
|
||||
|
||||
|
||||
class CreateVacancy(CreateAPIView):
|
||||
http_method_names = ("post",)
|
||||
serializer_class = VacancySerializer
|
||||
@@ -1,39 +1,32 @@
|
||||
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,),
|
||||
openapi.Info(title="SkillHub API", default_version="1")
|
||||
)
|
||||
|
||||
urlpatterns = [
|
||||
path("ping", include("api.ping.urls")),
|
||||
path("auth", include("api.users.urls")),
|
||||
path(
|
||||
"",
|
||||
include(
|
||||
"rest_framework.urls",
|
||||
namespace="rest_framework",
|
||||
),
|
||||
),
|
||||
path("teams", include("api.teams.urls")),
|
||||
# Built-in views
|
||||
path("admin/", admin.site.urls),
|
||||
# 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",
|
||||
schema_view.with_ui("swagger"),
|
||||
name="swagger",
|
||||
),
|
||||
path(
|
||||
"redoc/",
|
||||
schema_view.with_ui("redoc", cache_timeout=0),
|
||||
name="schema-redoc",
|
||||
schema_view.with_ui("redoc"),
|
||||
name="redoc",
|
||||
),
|
||||
path(
|
||||
"users/",
|
||||
include("api.users.urls", namespace="users"),
|
||||
),
|
||||
path(
|
||||
"events/",
|
||||
include("api.events.urls", namespace="events"),
|
||||
),
|
||||
]
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
from django.contrib import admin
|
||||
|
||||
from api.users.models import User
|
||||
|
||||
admin.site.register(User)
|
||||
@@ -1,11 +1,5 @@
|
||||
# Generated by Django 5.0.3 on 2024-04-01 14:59
|
||||
# Generated by Django 4.2.11 on 2024-04-02 17:05
|
||||
|
||||
import api.users.models
|
||||
import django.contrib.auth.models
|
||||
import django.contrib.auth.validators
|
||||
import django.core.validators
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
@@ -14,72 +8,24 @@ class Migration(migrations.Migration):
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('auth', '0012_alter_user_first_name_max_length'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Achievements',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('file', models.FileField(upload_to=api.users.models.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,
|
||||
},
|
||||
),
|
||||
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)])),
|
||||
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),
|
||||
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),
|
||||
('achievements', models.ManyToManyField(blank=True, to='users.achievements')),
|
||||
('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')),
|
||||
('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)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'user',
|
||||
'verbose_name_plural': 'users',
|
||||
'abstract': False,
|
||||
},
|
||||
managers=[
|
||||
('objects', django.contrib.auth.models.UserManager()),
|
||||
],
|
||||
),
|
||||
]
|
||||
|
||||
@@ -1,92 +1,15 @@
|
||||
import uuid
|
||||
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
from django.core import validators
|
||||
from django.db import models
|
||||
|
||||
from api.core.models import AbstractTag
|
||||
from api.core.models import BaseModel
|
||||
|
||||
|
||||
def get_file_path(filename):
|
||||
return f"achievements/{uuid.uuid4()}/{filename}"
|
||||
|
||||
|
||||
class Skill(AbstractTag):
|
||||
level = models.IntegerField(
|
||||
validators=[
|
||||
validators.MinValueValidator(1),
|
||||
validators.MaxValueValidator(10),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
class Achievements(models.Model):
|
||||
file = models.FileField(upload_to=get_file_path)
|
||||
info = models.TextField(
|
||||
max_length=255,
|
||||
)
|
||||
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)
|
||||
|
||||
def __str__(self):
|
||||
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 self.username
|
||||
return f"{self.first_name} {self.last_name}"
|
||||
|
||||
@@ -1,60 +1,24 @@
|
||||
from django.contrib.auth.hashers import check_password, make_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 Meta:
|
||||
model = User
|
||||
fields = (
|
||||
"email",
|
||||
"birthday",
|
||||
"avatar",
|
||||
"country",
|
||||
"city",
|
||||
"bio",
|
||||
"experience",
|
||||
"password",
|
||||
"first_name",
|
||||
"last_name",
|
||||
"specialization",
|
||||
"achievements",
|
||||
"username",
|
||||
"skills",
|
||||
)
|
||||
|
||||
extra_kwargs = {"password": {"write_only": True}}
|
||||
|
||||
def validate(self, attrs):
|
||||
if User.objects.filter(username=attrs["username"]).exists():
|
||||
raise serializers.ValidationError(
|
||||
{"username": "Username already exists"}
|
||||
)
|
||||
return super().validate(attrs)
|
||||
fields = "__all__"
|
||||
|
||||
def create(self, validated_data):
|
||||
validated_data["password"] = make_password(
|
||||
validated_data["password"],
|
||||
)
|
||||
return super().create(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
|
||||
|
||||
user = User.objects.create(**validated_data)
|
||||
event.users.add(user)
|
||||
|
||||
class ChangePasswordSerializer(serializers.Serializer):
|
||||
old_password = serializers.CharField(write_only=True)
|
||||
new_password = serializers.CharField(source="password", write_only=True)
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ("old_password", "new_password")
|
||||
|
||||
def validate_old_password(self, value):
|
||||
if not check_password(value, self.instance.password):
|
||||
msg = "Wrong password"
|
||||
raise serializers.ValidationError(msg)
|
||||
return value
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
instance.set_password(validated_data["password"])
|
||||
instance.save()
|
||||
return instance
|
||||
return user
|
||||
|
||||
@@ -1,41 +1,28 @@
|
||||
from django.urls import path
|
||||
from rest_framework_simplejwt.views import (
|
||||
TokenObtainPairView,
|
||||
TokenRefreshView,
|
||||
TokenVerifyView,
|
||||
from django.urls import include, path
|
||||
from rest_framework import routers
|
||||
|
||||
from api.users.views import (
|
||||
DownloadUsersFromExcelView,
|
||||
RegisterUsersFromExcelView,
|
||||
UserViewSet,
|
||||
)
|
||||
|
||||
import api.users.views
|
||||
app_name = "users"
|
||||
|
||||
router = routers.DefaultRouter()
|
||||
router.register("", UserViewSet)
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
path("", include(router.urls)),
|
||||
path(
|
||||
"/signup/",
|
||||
api.users.views.SignupUserApiView.as_view(),
|
||||
name="signup",
|
||||
"upload/excel/<event_id>/",
|
||||
RegisterUsersFromExcelView.as_view(),
|
||||
name="excel-upload",
|
||||
),
|
||||
path(
|
||||
"/sign-in/",
|
||||
TokenObtainPairView.as_view(),
|
||||
name="sign-in",
|
||||
),
|
||||
path(
|
||||
"api/token/refresh/",
|
||||
TokenRefreshView.as_view(),
|
||||
name="token_refresh",
|
||||
),
|
||||
path(
|
||||
"api/token/verify/",
|
||||
TokenVerifyView.as_view(),
|
||||
name="token_verify",
|
||||
),
|
||||
path(
|
||||
"/me/profile/",
|
||||
api.users.views.ProfileMeApiView.as_view(),
|
||||
name="profile-me",
|
||||
),
|
||||
path(
|
||||
"/me/password/",
|
||||
api.users.views.PasswordChangeApiView.as_view(),
|
||||
name="password-change",
|
||||
"download/excel/<event_id>/",
|
||||
DownloadUsersFromExcelView.as_view(),
|
||||
name="excel-download",
|
||||
),
|
||||
]
|
||||
|
||||
@@ -1,27 +1,81 @@
|
||||
from rest_framework.generics import CreateAPIView, UpdateAPIView
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
import io
|
||||
|
||||
from api.users.serializers import (
|
||||
ChangePasswordSerializer,
|
||||
UserSerializer,
|
||||
)
|
||||
import pandas as pd
|
||||
from django.http import FileResponse
|
||||
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.users.models import User
|
||||
from api.users.serializers import UserSerializer
|
||||
|
||||
|
||||
class SignupUserApiView(CreateAPIView):
|
||||
http_method_names = ("post",)
|
||||
class UserViewSet(ModelViewSet):
|
||||
queryset = User.objects.all()
|
||||
serializer_class = UserSerializer
|
||||
|
||||
|
||||
class ProfileMeApiView(UpdateAPIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
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,
|
||||
)
|
||||
|
||||
def get_object(self):
|
||||
return self.request.user
|
||||
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,
|
||||
)
|
||||
|
||||
try:
|
||||
data = pd.read_excel(excel_file)
|
||||
|
||||
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"],
|
||||
)
|
||||
|
||||
event.users.add(user)
|
||||
|
||||
return Response(
|
||||
{"success": "Users registered successfully"},
|
||||
status=status.HTTP_201_CREATED,
|
||||
)
|
||||
|
||||
except Exception as e: # noqa: BLE001
|
||||
return Response(
|
||||
{"error": str(e)}, status=status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
|
||||
|
||||
class PasswordChangeApiView(UpdateAPIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
serializer_class = ChangePasswordSerializer
|
||||
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,
|
||||
)
|
||||
|
||||
def get_object(self):
|
||||
return self.request.user
|
||||
serializer = UserSerializer(users, many=True)
|
||||
data = serializer.data
|
||||
|
||||
data = pd.DataFrame(data)
|
||||
|
||||
excel_data = io.BytesIO()
|
||||
data.to_excel(excel_data, index=False)
|
||||
excel_data.seek(0)
|
||||
|
||||
return FileResponse(excel_data, filename="users.xlsx")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import os
|
||||
|
||||
import django.core.asgi
|
||||
from django.core.asgi import get_asgi_application
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
|
||||
|
||||
application = django.core.asgi.get_asgi_application()
|
||||
application = get_asgi_application()
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
import pathlib
|
||||
import sys
|
||||
from datetime import timedelta
|
||||
from pathlib import Path
|
||||
|
||||
import environs
|
||||
from environs import Env
|
||||
|
||||
BASE_DIR = pathlib.Path(__file__).resolve().parent.parent
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
env = environs.Env()
|
||||
env = Env()
|
||||
env.read_env(BASE_DIR.parent / ".env")
|
||||
|
||||
DEFAULT_HOSTS = ["127.0.0.1", "localhost"]
|
||||
|
||||
with env.prefixed("DJANGO_"):
|
||||
SECRET_KEY = env("SECRET_KEY", "secret_key")
|
||||
SECRET_KEY = env("SECRET_KEY", "change-me")
|
||||
DEBUG = env.bool("DEBUG", True)
|
||||
ALLOWED_HOSTS = env.list("ALLOWED_HOSTS", DEFAULT_HOSTS)
|
||||
INTERNAL_IPS = env.list("INTERNAL_IPS", ALLOWED_HOSTS)
|
||||
@@ -24,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")
|
||||
POSTGRES_HOST = env("HOST", "localhost")
|
||||
POSTGRES_PORT = env("PORT", "5432")
|
||||
|
||||
|
||||
@@ -44,26 +43,24 @@ INSTALLED_APPS = [
|
||||
"django.contrib.staticfiles",
|
||||
# Third-party apps
|
||||
"rest_framework",
|
||||
"rest_framework_simplejwt",
|
||||
"corsheaders",
|
||||
"drf_yasg",
|
||||
# Developed apps
|
||||
"api.ping.apps.PingConfig",
|
||||
"api.users.apps.UsersConfig",
|
||||
"api.teams.apps.TeamsConfig",
|
||||
"api.core.apps.CoreConfig",
|
||||
"api.notifications.apps.NotificationsConfig",
|
||||
"api",
|
||||
"api.users",
|
||||
"api.events",
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
"corsheaders.middleware.CorsMiddleware",
|
||||
"django.middleware.common.CommonMiddleware",
|
||||
"django.middleware.security.SecurityMiddleware",
|
||||
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||
"django.middleware.common.CommonMiddleware",
|
||||
"django.middleware.csrf.CsrfViewMiddleware",
|
||||
"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"
|
||||
@@ -132,37 +129,23 @@ AUTH_PASSWORD_VALIDATORS = [
|
||||
},
|
||||
]
|
||||
|
||||
LANGUAGE_CODE = "en-us"
|
||||
USE_I18N = True
|
||||
LANGUAGE_CODE = "en-us"
|
||||
|
||||
USE_TZ = True
|
||||
TIME_ZONE = "UTC"
|
||||
USE_TZ = 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": [
|
||||
"rest_framework_simplejwt.authentication.JWTAuthentication",
|
||||
],
|
||||
}
|
||||
|
||||
CORS_ORIGIN_ALLOW_ALL = True
|
||||
|
||||
|
||||
SIMPLE_JWT = {
|
||||
"ACCESS_TOKEN_LIFETIME": timedelta(days=7),
|
||||
"REFRESH_TOKEN_LIFETIME": timedelta(days=30),
|
||||
}
|
||||
|
||||
|
||||
if DEBUG and not (TESTING or MIGRATING):
|
||||
INSTALLED_APPS.append("debug_toolbar")
|
||||
MIDDLEWARE.append("debug_toolbar.middleware.DebugToolbarMiddleware")
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
from django.conf import settings
|
||||
from django.contrib import admin
|
||||
from django.urls import include, path
|
||||
|
||||
urlpatterns = [
|
||||
# Built-in urls
|
||||
path("admin/", admin.site.urls),
|
||||
# API
|
||||
path("api/", include("api.urls")),
|
||||
]
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import os
|
||||
|
||||
import django.core.wsgi
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
|
||||
|
||||
application = django.core.wsgi.get_wsgi_application()
|
||||
application = get_wsgi_application()
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
[tool.ruff]
|
||||
line-length = 79
|
||||
indent-width = 4
|
||||
exclude = ["migrations", "venv", ".venv"]
|
||||
exclude = ["migrations"]
|
||||
|
||||
[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,6 +1,4 @@
|
||||
black
|
||||
sort-requirements
|
||||
ruff==0.3.4
|
||||
django-debug-toolbar==4.3.0
|
||||
|
||||
-r test.txt
|
||||
-r lint.txt
|
||||
|
||||
@@ -1,13 +1,30 @@
|
||||
django==4.2.11
|
||||
environs==11.0.0
|
||||
gunicorn==21.2.0
|
||||
python-dotenv==1.0.1
|
||||
psycopg2-binary==2.9.9
|
||||
djangorestframework==3.15.1
|
||||
djangorestframework-simplejwt==5.3.1
|
||||
asgiref==3.8.1
|
||||
Django==4.2.11
|
||||
django-cors-headers==4.3.1
|
||||
django-debug-toolbar==4.3.0
|
||||
django-filter==24.2
|
||||
Pillow==10.2.0
|
||||
djangorestframework==3.15.1
|
||||
drf-yasg==1.21.7
|
||||
django-cors-headers
|
||||
setuptools
|
||||
bcrypt==4.1.2
|
||||
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
|
||||
@@ -12,7 +12,7 @@ services:
|
||||
environment:
|
||||
POSTGRES_DB: ${POSTGRES_DB:-postgres}
|
||||
POSTGRES_USER: ${POSTGRES_USER:-postgres}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-8gDNJqx2D0hvH35}
|
||||
ports:
|
||||
- "${POSTGRES_PORT:-5432}:5432"
|
||||
volumes:
|
||||
@@ -29,7 +29,7 @@ services:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
POSTGRES_USER: ${POSTGRES_USER:-postgres}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-8gDNJqx2D0hvH35}
|
||||
POSTGRES_PORT: ${POSTGRES_PORT:-5432}
|
||||
POSTGRES_DB: ${POSTGRES_DB:-postgres}
|
||||
POSTGRES_HOST: postgres
|
||||
@@ -38,6 +38,7 @@ 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:
|
||||
@@ -56,6 +57,7 @@ services:
|
||||
- "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:
|
||||
@@ -69,7 +71,7 @@ services:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
PGADMIN_DEFAULT_EMAIL: ${PGADMIN_EMAIL:-admin@mail.com}
|
||||
PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_PASSWORD:-admin}
|
||||
PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_PASSWORD:-5tGnQhc2hEdb0nj}
|
||||
ports:
|
||||
- "${PGADMIN_PORT:-5050}:80"
|
||||
restart: always
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
|
||||
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
@@ -12,8 +13,8 @@
|
||||
--card-foreground: 240 10% 3.9%;
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 240 10% 3.9%;
|
||||
--primary: 240 5.9% 10%;
|
||||
--primary-foreground: 0 0% 98%;
|
||||
--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%;
|
||||
@@ -24,35 +25,36 @@
|
||||
--destructive-foreground: 0 0% 98%;
|
||||
--border: 240 5.9% 90%;
|
||||
--input: 240 5.9% 90%;
|
||||
--ring: 240 5.9% 10%;
|
||||
--ring: 142.1 76.2% 36.3%;
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--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%;
|
||||
--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: 240 3.7% 15.9%;
|
||||
--muted: 0 0% 15%;
|
||||
--muted-foreground: 240 5% 64.9%;
|
||||
--accent: 240 3.7% 15.9%;
|
||||
--accent: 12 6.5% 15.1%;
|
||||
--accent-foreground: 0 0% 98%;
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 0 0% 98%;
|
||||
--destructive-foreground: 0 85.7% 97.3%;
|
||||
--border: 240 3.7% 15.9%;
|
||||
--input: 240 3.7% 15.9%;
|
||||
--ring: 240 4.9% 83.9%;
|
||||
--ring: 142.4 71.8% 29.2%;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@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>React</title>
|
||||
<title>SkillHub</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
@@ -10,31 +10,43 @@
|
||||
"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",
|
||||
@@ -48,13 +60,17 @@
|
||||
"@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-react": "^7.34.1",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-react": "^7.34.1",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.6",
|
||||
"prettier": "^3.2.5"
|
||||
"postcss": "^8.4.32",
|
||||
"prettier": "^3.2.5",
|
||||
"tailwindcss": "^3.3.5",
|
||||
"vite": "^5.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
export default {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
@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,37 +7,60 @@ import {
|
||||
} from "react-router-dom";
|
||||
import Landing from "./components/pages/Landing/Landing";
|
||||
import Main from "./components/pages/Main/Main";
|
||||
import Teams from "./components/pages/Teams/Teams";
|
||||
import MyTeams from "./components/pages/MyTeams/MyTeams";
|
||||
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";
|
||||
|
||||
const router = createBrowserRouter([
|
||||
{
|
||||
path: "*",
|
||||
element: <TemplateWeb />,
|
||||
children: [{
|
||||
path: "",
|
||||
element: <Landing />,
|
||||
}]
|
||||
element: <TemplateWeb />,
|
||||
children: [
|
||||
{
|
||||
path: "",
|
||||
element: <Landing />
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: "*",
|
||||
element: <General />,
|
||||
children: [
|
||||
{
|
||||
path: "login",
|
||||
element: <Main />
|
||||
},
|
||||
{
|
||||
path: "successful",
|
||||
element: <Successful />
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: "dash",
|
||||
element: <General />,
|
||||
children: [{
|
||||
path: "main",
|
||||
element: <Main />,
|
||||
children: [
|
||||
{
|
||||
path: "eventlist",
|
||||
element: <AdminEventPage />
|
||||
},
|
||||
{
|
||||
path: "teams",
|
||||
element: <Teams />,
|
||||
path: "admin",
|
||||
element: <AdminPage />,
|
||||
children: [
|
||||
{
|
||||
path: "*",
|
||||
element: <AdminPage />
|
||||
}],
|
||||
},
|
||||
{
|
||||
path: "my-teams",
|
||||
element: <MyTeams />,
|
||||
},
|
||||
path: "skill-tree",
|
||||
element: <SkillTree />
|
||||
}
|
||||
]
|
||||
},
|
||||
])
|
||||
|
||||
}
|
||||
])
|
||||
function App() {
|
||||
return (
|
||||
<>
|
||||
|
||||
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 19 KiB |
@@ -0,0 +1,33 @@
|
||||
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>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,71 @@
|
||||
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>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,99 @@
|
||||
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>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,63 @@
|
||||
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>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,44 @@
|
||||
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>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,72 @@
|
||||
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>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,664 @@
|
||||
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>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,129 @@
|
||||
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>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
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>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,76 @@
|
||||
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>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,137 @@
|
||||
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>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
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,6 +1,10 @@
|
||||
// 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_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_REG = "registration/"
|
||||
export const API_CREATE_TOKEN = "token/"
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
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"
|
||||
@@ -10,12 +9,9 @@ function General() {
|
||||
return (
|
||||
<ThemeProvider defaultTheme="system" storageKey="vite-ui-theme">
|
||||
<Header />
|
||||
<div className={less['page-maket']}>
|
||||
<NavigationBar />
|
||||
<div className={less["main-content"]}>
|
||||
<main className={less["main-content"]}>
|
||||
<Outlet/>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</ThemeProvider>
|
||||
|
||||
)
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
.card{
|
||||
max-width: 800px;
|
||||
padding: 20px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
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,12 +1,11 @@
|
||||
.card-img{
|
||||
border: 2px solid #cdcdcd;
|
||||
border-radius: 8px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #d9d9d9;
|
||||
width: 30%;
|
||||
background: #d9d9d5
|
||||
}
|
||||
.card{
|
||||
width: 800px;
|
||||
max-width: 800px;
|
||||
padding: 20px;
|
||||
height: 230px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
@@ -1,18 +1,23 @@
|
||||
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 >
|
||||
<CardHeader className="p-0 pl-2">
|
||||
<CardTitle>Lorem ipsum</CardTitle>
|
||||
<CardDescription>Lorem ipsum</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<CardContent className="p-0 pl-2 mt-4">
|
||||
<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>
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
.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;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
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;
|
||||
@@ -0,0 +1,90 @@
|
||||
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: #d3d3d3;
|
||||
color: #595959;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,8 @@ const UserProfile = () => {
|
||||
<Card className={less.card}>
|
||||
<h1 className={less.h1}>Имя Фамилия</h1>
|
||||
<Separator />
|
||||
<p className={less.p}></p>
|
||||
<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>
|
||||
|
||||
</Card>
|
||||
</section>
|
||||
|
||||
@@ -1,41 +1,40 @@
|
||||
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"
|
||||
|
||||
|
||||
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";
|
||||
|
||||
export function ModeToggle() {
|
||||
const { setTheme } = useTheme()
|
||||
|
||||
const { t } = useTranslation();
|
||||
const { setTheme } = useTheme();
|
||||
|
||||
return (
|
||||
<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" />
|
||||
<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" />
|
||||
<span className="sr-only">Toggle theme</span>
|
||||
</Button>
|
||||
</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>
|
||||
)
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem onClick={() => setTheme("light")}>
|
||||
Light
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => setTheme("dark")}>
|
||||
Dark
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => setTheme("system")}>
|
||||
System
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
.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;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
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;
|
||||
@@ -0,0 +1,108 @@
|
||||
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);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
.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;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
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: 150px;
|
||||
font-size: 120px;
|
||||
line-height: 100%;
|
||||
text-transform: uppercase;
|
||||
|
||||
@@ -21,6 +21,67 @@
|
||||
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,21 +1,27 @@
|
||||
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";
|
||||
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";
|
||||
|
||||
function Landing() {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<><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>
|
||||
</>
|
||||
)
|
||||
<ThemeProvider>
|
||||
<Navbar />
|
||||
<Hero />
|
||||
<About />
|
||||
<HowItWorks />
|
||||
<Team />
|
||||
<FAQ />
|
||||
<Footer />
|
||||
<ScrollToTop />
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export default Landing
|
||||
export default Landing;
|
||||
|
||||
@@ -1,6 +1,66 @@
|
||||
.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,14 +1,124 @@
|
||||
import SearchBar from "../../features/SearchBar/SearchBar";
|
||||
import TeamsCard from "../../entities/TeamsCard/TeamsCard";
|
||||
import less from "./Main.module.less"
|
||||
|
||||
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";
|
||||
|
||||
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><SearchBar title="Вакансии" />
|
||||
</div><div className={less["general-content"]}>
|
||||
<TeamsCard />
|
||||
</div></>
|
||||
)
|
||||
}
|
||||
<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;
|
||||
@@ -1,7 +1,7 @@
|
||||
import TeamCard from "../../widgets/TeamCard/TeamCard";
|
||||
import TeamCard from "../../widgets/TeamInfoBlock/TeamInfoBlock";
|
||||
import UserProfile from "../../features/UserProfile/UserProfile";
|
||||
import less from "./MyTeams.module.less"
|
||||
import CreateTeam from "../../widgets/CreateTeam/CreateTeam";
|
||||
import CreateTeam from "../../widgets/CreateTeams/CreateTeams";
|
||||
|
||||
|
||||
const MyTeams = () => {
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
.general{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding-top: 80px;
|
||||
}
|
||||
.left{
|
||||
width: 50%;
|
||||
padding: 20px;
|
||||
padding-top: 0;
|
||||
}
|
||||
.right{
|
||||
width: 50%;
|
||||
|
||||
}
|
||||
.card{
|
||||
margin: 10px;
|
||||
padding: 10px;
|
||||
}
|
||||
.input-form{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
.title{
|
||||
padding: 0;
|
||||
}
|
||||
.up{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.header{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0;
|
||||
|
||||
}
|
||||
.h2{
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
}
|
||||