some progress?
4
TODO
|
@ -9,3 +9,7 @@ Naprogramovat:
|
||||||
|
|
||||||
Naplánovat:
|
Naplánovat:
|
||||||
- kurzy + cena: vyskakovací okno na rezervaci s jménem lekce? jak to vyřešit s kalendářem? (stránka /rezervace)
|
- kurzy + cena: vyskakovací okno na rezervaci s jménem lekce? jak to vyřešit s kalendářem? (stránka /rezervace)
|
||||||
|
|
||||||
|
|
||||||
|
DAVID:
|
||||||
|
- přidat posílání mailu panu vrchnímu
|
Before Width: | Height: | Size: 110 KiB |
|
@ -9,6 +9,8 @@ https://docs.djangoproject.com/en/5.1/topics/settings/
|
||||||
For the full list of settings and their values, see
|
For the full list of settings and their values, see
|
||||||
https://docs.djangoproject.com/en/5.1/ref/settings/
|
https://docs.djangoproject.com/en/5.1/ref/settings/
|
||||||
"""
|
"""
|
||||||
|
import os.path
|
||||||
|
|
||||||
import environ
|
import environ
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
@ -109,12 +111,6 @@ WSGI_APPLICATION = 'backend.wsgi.application'
|
||||||
# Database
|
# Database
|
||||||
# https://docs.djangoproject.com/en/5.1/ref/settings/#databases
|
# https://docs.djangoproject.com/en/5.1/ref/settings/#databases
|
||||||
|
|
||||||
# DATABASES = {
|
|
||||||
# 'default': {
|
|
||||||
# 'ENGINE': 'django.db.backends.sqlite3',
|
|
||||||
# 'NAME': BASE_DIR / 'db.sqlite3',
|
|
||||||
# }
|
|
||||||
# }
|
|
||||||
DATABASES = {
|
DATABASES = {
|
||||||
'default': env.db('DATABASE_URL')
|
'default': env.db('DATABASE_URL')
|
||||||
}
|
}
|
||||||
|
@ -142,9 +138,9 @@ AUTH_PASSWORD_VALIDATORS = [
|
||||||
# Internationalization
|
# Internationalization
|
||||||
# https://docs.djangoproject.com/en/5.1/topics/i18n/
|
# https://docs.djangoproject.com/en/5.1/topics/i18n/
|
||||||
|
|
||||||
LANGUAGE_CODE = 'en-us'
|
LANGUAGE_CODE = 'cs-cz'
|
||||||
|
|
||||||
TIME_ZONE = 'UTC'
|
TIME_ZONE = 'Europe/Prague'
|
||||||
|
|
||||||
USE_I18N = True
|
USE_I18N = True
|
||||||
|
|
||||||
|
@ -156,8 +152,14 @@ USE_TZ = True
|
||||||
|
|
||||||
STATIC_URL = '/static/'
|
STATIC_URL = '/static/'
|
||||||
|
|
||||||
|
STATICFILES_DIRS = [
|
||||||
|
os.path.join(BASE_DIR, 'static')
|
||||||
|
]
|
||||||
|
|
||||||
MEDIA_URL = '/media/'
|
MEDIA_URL = '/media/'
|
||||||
|
|
||||||
|
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
|
||||||
|
|
||||||
# Default primary key field type
|
# Default primary key field type
|
||||||
# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field
|
# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field
|
||||||
|
|
||||||
|
|
|
@ -18,11 +18,17 @@ from django.contrib import admin
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
from debug_toolbar.toolbar import debug_toolbar_urls
|
from debug_toolbar.toolbar import debug_toolbar_urls
|
||||||
|
|
||||||
from tko.views import ContactView, ArticleListView, EventListView
|
from django.conf.urls.static import static
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
from tko.views import ContactView, NewArticleListView, AllArticleListView, EventListView
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('admin/', admin.site.urls),
|
path('admin/', admin.site.urls),
|
||||||
path('create-contact/', ContactView.as_view(), name='create-contact'),
|
path('create-contact/', ContactView.as_view(), name='create-contact'),
|
||||||
path('load-articles/', ArticleListView.as_view(), name='load-articles'),
|
path('load-articles/', NewArticleListView.as_view(), name='load-articles'),
|
||||||
|
path('load-all-articles/', AllArticleListView.as_view(), name='load-all-articles'),
|
||||||
path('load-events/', EventListView.as_view(), name='load-events'),
|
path('load-events/', EventListView.as_view(), name='load-events'),
|
||||||
] + debug_toolbar_urls()
|
] + debug_toolbar_urls()
|
||||||
|
|
||||||
|
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
18
services/backend/tko/migrations/0004_alter_article_image.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 5.1.5 on 2025-02-21 16:37
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('tko', '0003_rename_first_name_contact_name_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='article',
|
||||||
|
name='image',
|
||||||
|
field=models.FileField(blank=True, default='default.png', upload_to=''),
|
||||||
|
),
|
||||||
|
]
|
|
@ -14,8 +14,8 @@ class Contact(models.Model):
|
||||||
class Article(models.Model):
|
class Article(models.Model):
|
||||||
title = models.CharField(max_length=100)
|
title = models.CharField(max_length=100)
|
||||||
content = models.TextField()
|
content = models.TextField()
|
||||||
image = models.FileField(upload_to='articles/%Y/%m/%d', null=True)
|
image = models.FileField(default="default.png", blank=True)
|
||||||
date = models.DateField()
|
date = models.DateField(auto_now_add=True)
|
||||||
author = models.CharField(max_length=100)
|
author = models.CharField(max_length=100)
|
||||||
|
|
||||||
active_to = models.DateField(null=True, blank=True) # do not show some invitation after this date
|
active_to = models.DateField(null=True, blank=True) # do not show some invitation after this date
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
from django.utils.timezone import localtime
|
||||||
|
|
||||||
from tko.models import Contact, Article, Event
|
from tko.models import Contact, Article, Event
|
||||||
|
|
||||||
|
@ -10,12 +11,29 @@ class ContactSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
|
|
||||||
class ArticleListSerializer(serializers.ModelSerializer):
|
class ArticleListSerializer(serializers.ModelSerializer):
|
||||||
|
date = serializers.SerializerMethodField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Article
|
model = Article
|
||||||
fields = '__all__'
|
fields = ["id", "author", "content", "date", "image", "title"]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_date(obj):
|
||||||
|
return obj.date.strftime("%-d. %-m. %Y")
|
||||||
|
|
||||||
|
|
||||||
class EventListSerializer(serializers.ModelSerializer):
|
class EventListSerializer(serializers.ModelSerializer):
|
||||||
|
start = serializers.SerializerMethodField()
|
||||||
|
end = serializers.SerializerMethodField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Event
|
model = Event
|
||||||
fields = '__all__'
|
fields = ["title", "end", "start", "color"]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_start(obj):
|
||||||
|
return localtime(obj.start_date).isoformat() if obj.start_date else None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_end(obj):
|
||||||
|
return localtime(obj.end_date).isoformat() if obj.end_date else None
|
|
@ -1,3 +1,6 @@
|
||||||
|
from django.utils import timezone
|
||||||
|
from django.db.models import Q
|
||||||
|
|
||||||
from rest_framework.generics import ListAPIView, CreateAPIView
|
from rest_framework.generics import ListAPIView, CreateAPIView
|
||||||
from rest_framework import permissions
|
from rest_framework import permissions
|
||||||
|
|
||||||
|
@ -10,11 +13,25 @@ class ContactView(CreateAPIView):
|
||||||
permission_classes = [permissions.AllowAny]
|
permission_classes = [permissions.AllowAny]
|
||||||
|
|
||||||
|
|
||||||
class ArticleListView(ListAPIView):
|
class NewArticleListView(ListAPIView):
|
||||||
queryset = Article.objects.all()
|
|
||||||
serializer_class = ArticleListSerializer
|
serializer_class = ArticleListSerializer
|
||||||
permission_classes = [permissions.AllowAny]
|
permission_classes = [permissions.AllowAny]
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return Article.objects.filter(
|
||||||
|
Q(active_to__gte=timezone.now()) | Q(active_to__isnull=True)
|
||||||
|
).order_by('-date')[:2]
|
||||||
|
|
||||||
|
|
||||||
|
class AllArticleListView(ListAPIView):
|
||||||
|
serializer_class = ArticleListSerializer
|
||||||
|
permission_classes = [permissions.AllowAny]
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return Article.objects.filter(
|
||||||
|
Q(active_to__gte=timezone.now()) | Q(active_to__isnull=True)
|
||||||
|
).order_by('-date')
|
||||||
|
|
||||||
|
|
||||||
class EventListView(ListAPIView):
|
class EventListView(ListAPIView):
|
||||||
queryset = Event.objects.all()
|
queryset = Event.objects.all()
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Playfair Display', serif;
|
font-family: 'Futura', sans-serif;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-display: block;
|
font-display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
font-family: 'Playfair Display', serif; /* Or a similar elegant font */
|
font-family: 'Futura', sans-serif;
|
||||||
font-size: 3rem;
|
font-size: 3rem;
|
||||||
color: #333; /* Dark gray */
|
color: #333;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
margin-top: 2rem;
|
margin-top: 2rem;
|
||||||
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.1); /* Subtle shadow */
|
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
font-family: 'Playfair Display', serif;
|
font-family: 'Futura', sans-serif;
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
color: #CF3476;
|
color: #CF3476;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
@ -24,25 +24,25 @@ h2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
font-family: 'Playfair Display', serif;
|
font-family: 'Futura', sans-serif;
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
color: #666; /* Light gray */
|
color: #666;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
h4 {
|
h4 {
|
||||||
font-family: 'Playfair Display', serif;
|
font-family: 'Futura', sans-serif;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
color: #666; /* Light gray */
|
color: #666;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
h5 {
|
h5 {
|
||||||
font-family: 'Playfair Display', serif;
|
font-family: 'Futura', sans-serif;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
color: #aaa; /* Light gray */
|
color: #aaa;
|
||||||
margin-top: 1rem;
|
margin-top: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,25 +52,30 @@ h5 {
|
||||||
margin-right: calc(20% - 2.5rem);
|
margin-right: calc(20% - 2.5rem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.app__logo {
|
||||||
|
height: 3.5rem;
|
||||||
|
width: 8rem;
|
||||||
|
}
|
||||||
|
|
||||||
.app__title {
|
.app__title {
|
||||||
font-family: 'Playfair Display', serif;
|
font-family: 'Futura', sans-serif;
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
color: #333; /* Light gray */
|
color: #333;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app__tab {
|
.app__tab {
|
||||||
font-family: 'Playfair Display', serif;
|
font-family: 'Futura', sans-serif;
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
color: #CF3476; /* Light gray */
|
color: #CF3476;
|
||||||
}
|
}
|
||||||
|
|
||||||
.to_left {
|
.to_left {
|
||||||
font-family: 'Playfair Display', serif;
|
font-family: 'Futura', sans-serif;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.to_right {
|
.to_right {
|
||||||
font-family: 'Playfair Display', serif;
|
font-family: 'Futura', sans-serif;
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,9 +89,9 @@ h5 {
|
||||||
.contact__title {
|
.contact__title {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 3rem;
|
font-size: 3rem;
|
||||||
color: #333; /* Dark gray */
|
color: #333;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
font-family: 'Playfair Display', serif;
|
font-family: 'Futura', sans-serif;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,71 +101,114 @@ h5 {
|
||||||
background-color: #CF3476;
|
background-color: #CF3476;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.articles {
|
||||||
|
margin-left: calc(20% - 2.5rem);
|
||||||
|
margin-right: calc(20% - 2.5rem);
|
||||||
|
}
|
||||||
|
|
||||||
.article {
|
.article {
|
||||||
padding: 20px;
|
padding: 10px;
|
||||||
min-width: 40%;
|
min-width: 40%;
|
||||||
border-radius: 15px;
|
border-radius: 15px;
|
||||||
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.3);
|
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.3);
|
||||||
margin: 50px
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article__image {
|
||||||
|
border-radius: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.article__title {
|
.article__title {
|
||||||
font-family: 'Playfair Display', serif;
|
font-family: 'Futura', sans-serif;
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
color: #CF3476; /* Dark gray */
|
color: #CF3476;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
margin-top: 0.1rem;
|
margin-top: 0.1rem;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.article__date {
|
.article__date {
|
||||||
font-family: 'Playfair Display', serif;
|
font-family: 'Futura', sans-serif;
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.article__text {
|
.article__text {
|
||||||
font-family: 'Playfair Display', serif; /* Or a similar elegant font */
|
font-family: 'Futura', sans-serif;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
color: #666; /* Dark gray */
|
min-height: 6rem;
|
||||||
|
color: #666;
|
||||||
}
|
}
|
||||||
|
|
||||||
.article__sign {
|
.article__sign {
|
||||||
font-family: 'Playfair Display', serif; /* Or a similar elegant font */
|
font-family: 'Futura', sans-serif;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
float: right;
|
float: right;
|
||||||
color: #333; /* Dark gray */
|
padding-right: 1rem;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.show_more {
|
||||||
|
font-family: 'Futura', sans-serif;
|
||||||
|
text-align: center;
|
||||||
|
color: #CF3476;
|
||||||
|
background: transparent;
|
||||||
|
box-shadow: none;
|
||||||
|
width: 300px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.show_more:hover {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pricing {
|
||||||
|
margin-left: calc(20% - 2.5rem);
|
||||||
|
margin-right: calc(20% - 2.5rem);
|
||||||
}
|
}
|
||||||
|
|
||||||
.pricing-box {
|
.pricing-box {
|
||||||
padding: 20px;
|
padding: 1rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
min-width: 25rem;
|
min-width: 25rem;
|
||||||
border-radius: 1rem;
|
border-radius: 1rem;
|
||||||
height: 230px;
|
height: 230px;
|
||||||
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.3);
|
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.3);
|
||||||
margin: 50px
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.pricing-box:not(:last-child) {
|
.pricing-box:hover {
|
||||||
margin: 20px;
|
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.8);
|
||||||
}
|
}
|
||||||
|
|
||||||
.pricing__price {
|
.pricing__price {
|
||||||
font-family: 'Playfair Display', serif; /* Or a similar elegant font */
|
font-family: 'Futura', sans-serif;
|
||||||
font-size: 3.5rem;
|
font-size: 3.5rem;
|
||||||
color: #CF3476; /* Dark gray */
|
color: #CF3476;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pricing__subtitle {
|
.pricing__subtitle {
|
||||||
font-family: 'Playfair Display', serif; /* Or a similar elegant font */
|
font-family: 'Futura', sans-serif;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
color: #333; /* Dark gray */
|
color: #333;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.trainers__parallax {
|
||||||
|
max-height: 34rem;
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trainers {
|
||||||
|
min-width: 25rem;
|
||||||
|
background: transparent;
|
||||||
|
box-shadow: none;
|
||||||
|
height: 100%;
|
||||||
|
margin-left: calc(20% - 2.5rem);
|
||||||
|
margin-right: calc(20% - 2.5rem);
|
||||||
|
}
|
||||||
|
|
||||||
.advantage {
|
.advantage {
|
||||||
min-width: 25rem;
|
min-width: 25rem;
|
||||||
border-radius: 1rem;
|
border-radius: 1rem;
|
||||||
|
@ -172,7 +220,7 @@ h5 {
|
||||||
}
|
}
|
||||||
|
|
||||||
.advantage__title {
|
.advantage__title {
|
||||||
font-family: 'Playfair Display', serif;
|
font-family: 'Futura', sans-serif;
|
||||||
color: #CF3476;
|
color: #CF3476;
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
@ -180,34 +228,37 @@ h5 {
|
||||||
}
|
}
|
||||||
|
|
||||||
.advantage__text {
|
.advantage__text {
|
||||||
font-family: 'Playfair Display', serif;
|
font-family: 'Futura', sans-serif;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
color: #333;
|
color: #333;
|
||||||
}
|
}
|
||||||
|
|
||||||
.about {
|
.about {
|
||||||
min-width: 25rem;
|
min-width: 25rem;
|
||||||
border-radius: 0;
|
|
||||||
background: transparent;
|
background: transparent;
|
||||||
|
box-shadow: none;
|
||||||
|
height: 100%;
|
||||||
|
margin-left: calc(20% - 2.5rem);
|
||||||
|
margin-right: calc(20% - 2.5rem);
|
||||||
}
|
}
|
||||||
|
|
||||||
.about__parallax {
|
.about__parallax {
|
||||||
max-height: 36rem;
|
max-height: 30rem;
|
||||||
|
margin-top: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.about__title {
|
.about__title {
|
||||||
font-family: 'Playfair Display', serif;
|
font-family: 'Futura', sans-serif;
|
||||||
font-size: 3rem;
|
font-size: 3rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: #ddd; /* Dark gray */
|
color: #fff;
|
||||||
margin-bottom: 1rem;
|
|
||||||
margin-top: 1rem;
|
margin-top: 1rem;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.about__subtitle {
|
.about__subtitle {
|
||||||
font-family: 'Playfair Display', serif;
|
font-family: 'Futura', sans-serif;
|
||||||
color: #CF3476;
|
color: #FF3D8C;
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
|
@ -215,8 +266,12 @@ h5 {
|
||||||
}
|
}
|
||||||
|
|
||||||
.about__text {
|
.about__text {
|
||||||
font-family: 'Playfair Display', serif;
|
font-family: 'Futura', sans-serif;
|
||||||
color: #aaa; /* Dark gray */
|
color: #ddd;
|
||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
background-color: black;
|
||||||
|
}
|
|
@ -1,35 +1,21 @@
|
||||||
<template>
|
<template>
|
||||||
<v-parallax
|
<v-parallax
|
||||||
src="https://www.danceus.org/parse/files/Bjy5anNVI0Q81M8bmrwIiuU20x4kepQTxzDBfqpR/70d831b8f51edc1f6e1a4320d52f164b_latin-dance.jpg"
|
|
||||||
class="about__parallax"
|
class="about__parallax"
|
||||||
|
src="public/dark-dance.jpg"
|
||||||
|
scale="0.8"
|
||||||
>
|
>
|
||||||
<v-container fluid fill-height id="about">
|
<v-container id="about">
|
||||||
<v-row align="center" justify="center">
|
|
||||||
<v-col
|
|
||||||
cols="12"
|
|
||||||
md="4"
|
|
||||||
/>
|
|
||||||
<v-col
|
|
||||||
cols="12"
|
|
||||||
md="8"
|
|
||||||
style="color: white; padding: 50px"
|
|
||||||
>
|
|
||||||
<v-card class="about">
|
<v-card class="about">
|
||||||
<v-card-title class="about__title">Vítejte v tanečním klubu!</v-card-title>
|
<v-card-title class="about__title">Vítejte v tanečním klubu!</v-card-title>
|
||||||
<v-card-subtitle class="about__subtitle">Tanec je vášeň!</v-card-subtitle>
|
<v-card-subtitle class="about__subtitle">Vítejte na webu Tanečního klubu Ostrava!</v-card-subtitle>
|
||||||
<v-card-text class="about__text">
|
<v-card-text class="about__text">
|
||||||
Sportovní taneční klub jsme založili v roce 2016 s absolventy středoškolských tanečních kurzů taneční školy Bolero Ostrava.
|
Objevte kouzlo tance s námi! Ať už jste začátečník nebo zkušený tanečník, v našem klubu najdete místo, kde se můžete rozvíjet, bavit a sdílet svou vášeň pro pohyb. Nabízíme kurzy pro všechny věkové kategorie, od společenských tanců po moderní styly.
|
||||||
Společně jsme se zaměřili na profesionální stránku tance, našli jsme pár aktivních tanečníků se kterými jsme začali pravidelně trénovat pohyb, krokové variace a techniku jednotlivých tanců.
|
|
||||||
Po roce tréninků se dostavily i první výsledky a dnes již tito mladí tanečníci skvěle reprezentují klub na celé řadě tanečních soutěží.
|
|
||||||
<br><br>
|
<br><br>
|
||||||
O rok později v roce 2017 jsme založili také společenský taneční klub pro dospělé, kteří by se rádi také tanci věnovali.
|
Přidejte se k nám a nechte tanec proměnit váš život! 💃🕺
|
||||||
Příjemná atmosféra, zábava, ale i chuť se učit novým věcem, to jsou tři slova, které by mohly charakterizovat atmosféru v tanečních lekcích.
|
<br><br>
|
||||||
Taneční klub, ať už sportovní tak i společenský vítá všechny milovníky tance, kteří chtějí poodhalit tajemství ladných tanečních pohybů, sdílet nezaměnitelnou atmosféru a dovědět se více o taneční technice.
|
👉 Podívejte se na naše kurzy a přihlaste se ještě dnes!
|
||||||
Našim přáním je, abyste na tanečním parketu jednoduše zářili.
|
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
</v-container>
|
</v-container>
|
||||||
</v-parallax>
|
</v-parallax>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<h1>Co dostanete s tanečním klubem</h1>
|
<h1>Přínosy tance: Více než jen pohyb</h1>
|
||||||
<h2>Výhody tanečníka</h2>
|
<h2>Tancem k lepšímu životu</h2>
|
||||||
<v-card
|
<v-card
|
||||||
v-for="advantage in advantages"
|
v-for="advantage in advantages"
|
||||||
:key="advantage.id"
|
:key="advantage.id"
|
||||||
|
|
|
@ -4,13 +4,14 @@
|
||||||
|
|
||||||
<v-sheet class="sheet__box">
|
<v-sheet class="sheet__box">
|
||||||
<v-calendar
|
<v-calendar
|
||||||
v-model="value"
|
:firstDayOfWeek="0"
|
||||||
first-day-of-week="1"
|
|
||||||
locale="cs-CZ"
|
locale="cs-CZ"
|
||||||
ref="calendar"
|
ref="calendar"
|
||||||
|
:showAdjacentMonths="true"
|
||||||
view-mode="week"
|
view-mode="week"
|
||||||
:events="events"
|
:events="events"
|
||||||
:weekdays="[1, 2, 3, 4, 5, 6, 0]"
|
:interval-start="7"
|
||||||
|
:interval-height="25"
|
||||||
/>
|
/>
|
||||||
</v-sheet>
|
</v-sheet>
|
||||||
</template>
|
</template>
|
||||||
|
@ -19,16 +20,28 @@
|
||||||
import './assets/css/main.css'
|
import './assets/css/main.css'
|
||||||
import {useAPI} from "~/composables/useAPI";
|
import {useAPI} from "~/composables/useAPI";
|
||||||
|
|
||||||
|
interface Event {
|
||||||
const { error, data } = await useAPI('load-events/', {method: "GET"});
|
title: string;
|
||||||
|
end: Date;
|
||||||
const value = [new Date()];
|
start: Date;
|
||||||
const events = [
|
color: string;
|
||||||
{
|
}
|
||||||
title: "ahoj",
|
|
||||||
start: new Date(),
|
const events = ref<Event[]>([]);
|
||||||
end: new Date(),
|
|
||||||
color: 'red',
|
await loadEvents();
|
||||||
|
|
||||||
|
async function loadEvents() {
|
||||||
|
const { error, data } = await useAPI<Event[]>('load-events/', { method: "GET" });
|
||||||
|
|
||||||
|
if (data.value && Array.isArray(data.value)) {
|
||||||
|
events.value = data.value as Event[];
|
||||||
|
for(const i in data.value){
|
||||||
|
data.value[i].end = new Date((data.value[i].end));
|
||||||
|
data.value[i].start = new Date((data.value[i].start));
|
||||||
|
}
|
||||||
|
} else if (error.value) {
|
||||||
|
console.error("Error loading events:", error.value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
];
|
|
||||||
</script>
|
</script>
|
|
@ -72,8 +72,8 @@ const email = ref<string>("");
|
||||||
const phone = ref<string>("");
|
const phone = ref<string>("");
|
||||||
const textField = ref<string>("");
|
const textField = ref<string>("");
|
||||||
|
|
||||||
function sendContact() {
|
async function sendContact() {
|
||||||
useAPI('create-contact/', {
|
const { data, error } = await useAPI('create-contact/', {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: {
|
body: {
|
||||||
name: fullName.value,
|
name: fullName.value,
|
||||||
|
|
|
@ -1,30 +1,41 @@
|
||||||
<template>
|
<template>
|
||||||
<h1 id="courses">Kurzy - cena</h1>
|
<h1 id="courses">Kurzy</h1>
|
||||||
<h2>Vyberte, co Vám nejlépe vyhovuje</h2>
|
<h2>Vyberte, co Vám nejlépe vyhovuje</h2>
|
||||||
|
|
||||||
<v-row>
|
<v-row class="pricing">
|
||||||
<v-col
|
<v-col
|
||||||
cols="12"
|
cols="12"
|
||||||
md="4"
|
md="4"
|
||||||
v-for="course in courses"
|
v-for="(course, index) in courses"
|
||||||
:key="course.id"
|
:key="index"
|
||||||
>
|
>
|
||||||
<v-card class="pricing-box">
|
<v-card class="pricing-box">
|
||||||
<h3>{{ course.name }}</h3>
|
<h3>{{ course.name }}</h3>
|
||||||
<v-card-subtitle><div class="pricing__subtitle">{{ course.time }}</div></v-card-subtitle>
|
<v-card-subtitle><div class="pricing__subtitle">{{ course.time }}</div></v-card-subtitle>
|
||||||
<v-card-title><div class="pricing__price">{{ course.price }}</div></v-card-title>
|
<v-card-title><div class="pricing__price">{{ course.price }}</div></v-card-title>
|
||||||
<v-card-subtitle v-if="course.desc"><div class="pricing__subtitle">{{ course.desc }}</div></v-card-subtitle>
|
<v-card-text v-if="course.desc"><div class="pricing__subtitle">{{ course.desc }}</div></v-card-text>
|
||||||
|
<v-btn class="show_more">
|
||||||
|
Kontaktujte nás
|
||||||
|
</v-btn>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
|
<!-- <v-btn to="/kurzy" class="show_more">-->
|
||||||
|
<!-- <v-icon icon="mdi-chevron-down"/>Více informací<v-icon icon="mdi-chevron-down"/>-->
|
||||||
|
<!-- </v-btn>-->
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import './assets/css/main.css'
|
import './assets/css/main.css'
|
||||||
|
|
||||||
|
// TODO: vyskakovací okno s kontaktním formulářem po rozkliku :)
|
||||||
|
|
||||||
const courses = [
|
const courses = [
|
||||||
{id: 1, name: "Sportovní taneční klub", time: "24 hodin/měsíc", price: "600 Kč", desc: false},
|
{name: "Sportovní taneční klub", time: "", price: "", desc: "Připojte se k našemu tanečnímu klubu a rozvíjejte své taneční dovednosti v přátelském prostředí. Nabízíme různé styly tance pro všechny úrovně."},
|
||||||
{id: 2, name: "Individuální lekce", time: "60min / taneční pár", price: "500 Kč", desc: "Pro veřejnost"},
|
{name: "Svatební tance", time: "", price: "", desc: "Udělejte svůj první tanec nezapomenutelným. Pomůžeme Vám vytvořit choreografii na míru, která bude odrážet Váš jedinečný styl."},
|
||||||
{id: 3, name: "Volný trénink s lektorem", time: "60min / taneční pár", price: "100 Kč", desc: "Pro členy tanečního klubu"},
|
{name: "Příprava na plesovou sezónu", time: "", price: "", desc: "Chcete zazářit na plese? Připravíme Vás na plesovou sezónu a naučíme Vás elegantní taneční kroky a etiketu."},
|
||||||
|
{name: "Individuální taneční kurzy", time: "", price: "", desc: "Učte se tančit vlastním tempem s individuálním přístupem. Naši zkušení lektoři se zaměří na Vaše potřeby a pomohou Vám dosáhnout Vašich tanečních cílů."},
|
||||||
|
{name: "Individuální lekce", time: "", price: "", desc: "Zlepšete své taneční dovednosti s intenzivními individuálními lekcemi. Zaměřte se na konkrétní taneční techniky nebo styly, které Vás zajímají."},
|
||||||
|
{name: "Pronájem sálu", time: "", price: "", desc: "Hledáte ideální prostor pro tanec nebo jinou aktivitu? Náš taneční sál je k dispozici k pronájmu pro Vaše akce."},
|
||||||
]
|
]
|
||||||
|
|
||||||
</script>
|
</script>
|
27
services/frontend/components/History.vue
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<template>
|
||||||
|
<v-parallax
|
||||||
|
class="about__parallax"
|
||||||
|
src="public/img/black-pink.jpg"
|
||||||
|
>
|
||||||
|
<v-container id="about">
|
||||||
|
<v-card class="about">
|
||||||
|
<v-card-title class="about__title">Vítejte v tanečním klubu!</v-card-title>
|
||||||
|
<v-card-subtitle class="about__subtitle">Tanec je vášeň!</v-card-subtitle>
|
||||||
|
<v-card-text class="about__text">
|
||||||
|
Sportovní taneční klub jsme založili v roce 2016 s absolventy středoškolských tanečních kurzů taneční školy Bolero Ostrava.
|
||||||
|
Společně jsme se zaměřili na profesionální stránku tance, našli jsme pár aktivních tanečníků se kterými jsme začali pravidelně trénovat pohyb, krokové variace a techniku jednotlivých tanců.
|
||||||
|
Po roce tréninků se dostavily i první výsledky a dnes již tito mladí tanečníci skvěle reprezentují klub na celé řadě tanečních soutěží.
|
||||||
|
<br><br>
|
||||||
|
O rok později v roce 2017 jsme založili také společenský taneční klub pro dospělé, kteří by se rádi také tanci věnovali.
|
||||||
|
Příjemná atmosféra, zábava, ale i chuť se učit novým věcem, to jsou tři slova, které by mohly charakterizovat atmosféru v tanečních lekcích.
|
||||||
|
Taneční klub, ať už sportovní tak i společenský vítá všechny milovníky tance, kteří chtějí poodhalit tajemství ladných tanečních pohybů, sdílet nezaměnitelnou atmosféru a dovědět se více o taneční technice.
|
||||||
|
Našim přáním je, abyste na tanečním parketu jednoduše zářili.
|
||||||
|
</v-card-text>
|
||||||
|
</v-card>
|
||||||
|
</v-container>
|
||||||
|
</v-parallax>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import './assets/css/main.css'
|
||||||
|
</script>
|
|
@ -1,10 +1,10 @@
|
||||||
<template>
|
<template v-if="articles">
|
||||||
<h1 id="article">Aktuality</h1>
|
<h1 id="article">Aktuality</h1>
|
||||||
<h2>Přečtěte si aktuality z našeho klubu</h2>
|
<h2>Přečtěte si aktuality z našeho klubu</h2>
|
||||||
<v-row>
|
<v-row class="articles">
|
||||||
<v-col
|
<v-col
|
||||||
v-for="(article, index) in articles"
|
v-for="article in articles"
|
||||||
:key="index"
|
:key="article.id"
|
||||||
cols="12"
|
cols="12"
|
||||||
md="6"
|
md="6"
|
||||||
>
|
>
|
||||||
|
@ -12,10 +12,11 @@
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col>
|
<v-col>
|
||||||
<v-img
|
<v-img
|
||||||
:lazy-src="article.src"
|
:lazy-src="article.image"
|
||||||
:src="article.src"
|
:src="article.image"
|
||||||
aspect-ratio="1"
|
aspect-ratio="1"
|
||||||
cover
|
cover
|
||||||
|
class="article__image"
|
||||||
>
|
>
|
||||||
<template v-slot:placeholder>
|
<template v-slot:placeholder>
|
||||||
<v-row>
|
<v-row>
|
||||||
|
@ -33,29 +34,41 @@
|
||||||
>
|
>
|
||||||
<v-row class="article__title">{{ article.title }}</v-row>
|
<v-row class="article__title">{{ article.title }}</v-row>
|
||||||
<v-row class="article__date">{{ article.date}}</v-row>
|
<v-row class="article__date">{{ article.date}}</v-row>
|
||||||
<v-row class="article__text">{{ article.desc }}</v-row>
|
<v-row class="article__text">{{ article.content }}</v-row>
|
||||||
<v-row class="article__sign">{{ article.autor }}</v-row>
|
<v-row class="article__sign">{{ article.author }}</v-row>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
|
<v-btn to="/aktuality" class="show_more">
|
||||||
|
<v-icon icon="mdi-chevron-down"/>Dalsí aktuality<v-icon icon="mdi-chevron-down"/>
|
||||||
|
</v-btn>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import './assets/css/main.css'
|
import './assets/css/main.css'
|
||||||
|
|
||||||
import { useAPI } from "~/composables/useAPI";
|
import { useAPI } from "~/composables/useAPI";
|
||||||
|
|
||||||
const { error, data } = await useAPI('load-articles/', {method: "GET"});
|
interface Article {
|
||||||
console.log(error.value);
|
id: number;
|
||||||
|
title: string;
|
||||||
|
image: string;
|
||||||
|
date: string;
|
||||||
|
content: string;
|
||||||
|
author: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const articles = ref<Article[]>([]);
|
||||||
|
|
||||||
|
const { error, data } = await useAPI<Article[]>('load-articles/', {method: "GET"});
|
||||||
|
|
||||||
|
if ( data.value ){
|
||||||
|
articles.value = data.value;
|
||||||
|
}
|
||||||
|
else if (error.value) {
|
||||||
|
console.error("Error loading articles:", error.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const articles = [
|
|
||||||
{
|
|
||||||
autor: "Bebloid Obecný",
|
|
||||||
date: "2. 2. 2025",
|
|
||||||
title: "David potrolil soutěž",
|
|
||||||
src: "/terka&david.jpg",
|
|
||||||
desc: "V neděli 2. 2. David potrolil sambu, kde místo tančení lítal jako zmatená včelka. Terka, ačkoliv před soutěží velice zmatkovala a sebepoškozovala se, tak na parketě předvedla výborné představení. Na další trolení se můžeme všichni těšit do Brna na konci tohoto měsíce. "
|
|
||||||
},
|
|
||||||
]
|
|
||||||
</script>
|
</script>
|
|
@ -1,7 +1,13 @@
|
||||||
<template>
|
<template>
|
||||||
<h1 id="trainers">Naši trenéři a lektoři</h1>
|
<v-parallax
|
||||||
<h2>Seznamte se s námi!</h2>
|
class="trainers__parallax"
|
||||||
<v-row style="margin-bottom: 2rem;">
|
src="public/img/black-pink.jpg"
|
||||||
|
>
|
||||||
|
<v-container id="trainers">
|
||||||
|
<v-card class="trainers">
|
||||||
|
<v-card-title class="about__title">Naši trenéři a lektoři</v-card-title>
|
||||||
|
<v-card-subtitle class="about__subtitle">Seznamte se s námi!</v-card-subtitle>
|
||||||
|
<v-row>
|
||||||
<v-col class="text-center" cols="12" md="3" v-for="lector in lectors" :key="lector.id">
|
<v-col class="text-center" cols="12" md="3" v-for="lector in lectors" :key="lector.id">
|
||||||
<v-avatar
|
<v-avatar
|
||||||
color="none"
|
color="none"
|
||||||
|
@ -11,10 +17,13 @@
|
||||||
>
|
>
|
||||||
<v-img :src="lector.img" cover></v-img>
|
<v-img :src="lector.img" cover></v-img>
|
||||||
</v-avatar>
|
</v-avatar>
|
||||||
<h2>{{lector.name}}</h2>
|
<v-card-subtitle class="about__subtitle">{{lector.name}}</v-card-subtitle>
|
||||||
<h4>{{ lector.desc }}</h4>
|
<v-card-text class="about__text">{{ lector.desc }}</v-card-text>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
|
</v-card>
|
||||||
|
</v-container>
|
||||||
|
</v-parallax>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import './assets/css/main.css'
|
import './assets/css/main.css'
|
||||||
|
@ -23,25 +32,25 @@ const lectors = [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
name: "Ondřej Gilar",
|
name: "Ondřej Gilar",
|
||||||
img: "/Beblik.jpg",
|
img: "/trainers/img.png",
|
||||||
desc: "Trenér - latinskoamerické tance a Pro-AM",
|
desc: "Trenér - latinskoamerické tance a Pro-AM",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
name: "Leona Hruštincová",
|
name: "Leona Hruštincová",
|
||||||
img: "https://cdn.vuetifyjs.com/images/profiles/marcus.jpg",
|
img: "/trainers/img.png",
|
||||||
desc: "Lektorka - tance pro děti",
|
desc: "Lektorka - tance pro děti",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
name: "Ondřej Gilar",
|
name: "Ondřej Gilar",
|
||||||
img: "https://cdn.vuetifyjs.com/images/profiles/marcus.jpg",
|
img: "/trainers/img.png",
|
||||||
desc: "Trenér - latinskoamerické tance a Pro-AM",
|
desc: "Trenér - latinskoamerické tance a Pro-AM",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
name: "Leona Hruštincová",
|
name: "Leona Hruštincová",
|
||||||
img: "https://cdn.vuetifyjs.com/images/profiles/marcus.jpg",
|
img: "/trainers/img.png",
|
||||||
desc: "Lektorka - tance pro děti",
|
desc: "Lektorka - tance pro děti",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<v-footer
|
<v-footer class="footer">
|
||||||
style="background-color: black"
|
|
||||||
>
|
|
||||||
<v-container class="text-white">
|
<v-container class="text-white">
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col
|
<v-col
|
||||||
|
@ -47,7 +45,7 @@
|
||||||
<v-col
|
<v-col
|
||||||
style="text-align: left"
|
style="text-align: left"
|
||||||
>
|
>
|
||||||
<h5>Taneční klub Ostrava © 2025</h5>
|
<h5>Taneční klub Ostrava s.r.o. © {{date}}</h5>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col
|
<v-col
|
||||||
style="text-align: right"
|
style="text-align: right"
|
||||||
|
@ -61,4 +59,5 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import './assets/css/main.css'
|
import './assets/css/main.css'
|
||||||
|
|
||||||
|
const date = new Date().getFullYear()
|
||||||
</script>
|
</script>
|
|
@ -6,7 +6,9 @@
|
||||||
@click="drawer = !drawer"
|
@click="drawer = !drawer"
|
||||||
class="d-flex d-sm-none"
|
class="d-flex d-sm-none"
|
||||||
/>
|
/>
|
||||||
<a href="/"><big-icon icon="mdi-dance-ballroom" /></a>
|
<div>
|
||||||
|
<a href="/"><v-img class="app__logo" src="/logo.png" /></a>
|
||||||
|
</div>
|
||||||
<v-app-bar-title class="app__title">Taneční klub Ostrava</v-app-bar-title>
|
<v-app-bar-title class="app__title">Taneční klub Ostrava</v-app-bar-title>
|
||||||
|
|
||||||
<v-tabs
|
<v-tabs
|
||||||
|
@ -18,8 +20,6 @@
|
||||||
<v-tab v-if="tab.ref" :text="tab.name" :value="tab.name" @click="useGoTo(tab.ref)"></v-tab>
|
<v-tab v-if="tab.ref" :text="tab.name" :value="tab.name" @click="useGoTo(tab.ref)"></v-tab>
|
||||||
<v-tab v-if="tab.href" :text="tab.name" :value="tab.name" :href="tab.href"></v-tab>
|
<v-tab v-if="tab.href" :text="tab.name" :value="tab.name" :href="tab.href"></v-tab>
|
||||||
</v-tabs>
|
</v-tabs>
|
||||||
|
|
||||||
|
|
||||||
<!-- <v-col-->
|
<!-- <v-col-->
|
||||||
<!-- class="text-right"-->
|
<!-- class="text-right"-->
|
||||||
<!-- @click="toggleTheme"-->
|
<!-- @click="toggleTheme"-->
|
||||||
|
@ -43,11 +43,9 @@
|
||||||
nav
|
nav
|
||||||
dense
|
dense
|
||||||
>
|
>
|
||||||
<v-list-item>
|
|
||||||
<v-list-item v-for="(tab, index) in tabs" :key="index">
|
<v-list-item v-for="(tab, index) in tabs" :key="index">
|
||||||
<v-list-item-title @click="useGoTo(tab.ref)">{{ tab.name }}</v-list-item-title>
|
<v-list-item-title @click="useGoTo(tab.ref)">{{ tab.name }}</v-list-item-title>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
</v-list-item>
|
|
||||||
</v-list>
|
</v-list>
|
||||||
</v-navigation-drawer>
|
</v-navigation-drawer>
|
||||||
</v-layout>
|
</v-layout>
|
||||||
|
@ -55,46 +53,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
function waitForElement (selector: string, timeout = 2000) : Promise<Element> {
|
import { useGoTo } from "~/composables/useGoTo";
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const startTime = Date.now();
|
|
||||||
// eslint-disable-next-line prefer-const
|
|
||||||
let observer: MutationObserver;
|
|
||||||
|
|
||||||
function checkElement () {
|
|
||||||
const element = document.querySelector(selector);
|
|
||||||
|
|
||||||
if (element) {
|
|
||||||
resolve(element);
|
|
||||||
observer.disconnect(); // Stop observing DOM changes
|
|
||||||
} else if (Date.now() - startTime >= timeout) {
|
|
||||||
reject(new Error(`Timeout exceeded while waiting for element with selector '${selector}'`));
|
|
||||||
observer.disconnect(); // Stop observing DOM changes
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
observer = new MutationObserver(checkElement);
|
|
||||||
observer.observe(document.body, { childList: true, subtree: true });
|
|
||||||
|
|
||||||
checkElement(); // Check initially in case the element is already present
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async function useGoTo (selector: string, props: {offset? :number} = {}): Promise<void> {
|
|
||||||
console.log(selector);
|
|
||||||
let element: Element;
|
|
||||||
try {
|
|
||||||
element = await waitForElement(selector);
|
|
||||||
} catch {
|
|
||||||
// element not found
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const yOffset = props?.offset ?? -80;
|
|
||||||
const y = element.getBoundingClientRect().top + window.pageYOffset + yOffset;
|
|
||||||
|
|
||||||
window.scrollTo({ top: y, behavior: "smooth" });
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentTab = ref({name: 'O nás', ref: "#about", href: "o-nas"});
|
const currentTab = ref({name: 'O nás', ref: "#about", href: "o-nas"});
|
||||||
const drawer = ref(null)
|
const drawer = ref(null)
|
||||||
|
|
40
services/frontend/composables/useGoTo.ts
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
function waitForElement (selector: string, timeout = 2000) : Promise<Element> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const startTime = Date.now();
|
||||||
|
// eslint-disable-next-line prefer-const
|
||||||
|
let observer: MutationObserver;
|
||||||
|
|
||||||
|
function checkElement () {
|
||||||
|
const element = document.querySelector(selector);
|
||||||
|
|
||||||
|
if (element) {
|
||||||
|
resolve(element);
|
||||||
|
observer.disconnect(); // Stop observing DOM changes
|
||||||
|
} else if (Date.now() - startTime >= timeout) {
|
||||||
|
reject(new Error(`Timeout exceeded while waiting for element with selector '${selector}'`));
|
||||||
|
observer.disconnect(); // Stop observing DOM changes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
observer = new MutationObserver(checkElement);
|
||||||
|
observer.observe(document.body, { childList: true, subtree: true });
|
||||||
|
|
||||||
|
checkElement(); // Check initially in case the element is already present
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export async function useGoTo (selector: string, props: {offset? :number} = {}): Promise<void> {
|
||||||
|
console.log(selector);
|
||||||
|
let element: Element;
|
||||||
|
try {
|
||||||
|
element = await waitForElement(selector);
|
||||||
|
} catch {
|
||||||
|
// element not found
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const yOffset = props?.offset ?? -80;
|
||||||
|
const y = element.getBoundingClientRect().top + window.pageYOffset + yOffset;
|
||||||
|
|
||||||
|
window.scrollTo({ top: y, behavior: "smooth" });
|
||||||
|
}
|
70
services/frontend/pages/aktuality.vue
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
<template v-if="articles">
|
||||||
|
<h1 id="article">Aktuality</h1>
|
||||||
|
<h2>Přečtěte si aktuality z našeho klubu</h2>
|
||||||
|
<v-row>
|
||||||
|
<v-col
|
||||||
|
v-for="article in articles"
|
||||||
|
:key="article.id"
|
||||||
|
cols="12"
|
||||||
|
md="6"
|
||||||
|
>
|
||||||
|
<v-card class="article">
|
||||||
|
<v-row>
|
||||||
|
<v-col>
|
||||||
|
<v-img
|
||||||
|
:lazy-src="article.image"
|
||||||
|
:src="article.image"
|
||||||
|
aspect-ratio="1"
|
||||||
|
cover
|
||||||
|
class="article__image"
|
||||||
|
>
|
||||||
|
<template v-slot:placeholder>
|
||||||
|
<v-row>
|
||||||
|
<v-progress-circular
|
||||||
|
color="grey-lighten-5"
|
||||||
|
indeterminate
|
||||||
|
></v-progress-circular>
|
||||||
|
</v-row>
|
||||||
|
</template>
|
||||||
|
</v-img>
|
||||||
|
</v-col>
|
||||||
|
<v-col
|
||||||
|
cols="12"
|
||||||
|
md="8"
|
||||||
|
>
|
||||||
|
<v-row class="article__title">{{ article.title }}</v-row>
|
||||||
|
<v-row class="article__date">{{ article.date}}</v-row>
|
||||||
|
<v-row class="article__text">{{ article.content }}</v-row>
|
||||||
|
<v-row class="article__sign">{{ article.author }}</v-row>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</v-card>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import './assets/css/main.css'
|
||||||
|
|
||||||
|
import {useAPI} from "~/composables/useAPI";
|
||||||
|
|
||||||
|
interface Article {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
image: string;
|
||||||
|
date: string;
|
||||||
|
content: string;
|
||||||
|
author: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const articles = ref<Article[]>([]);
|
||||||
|
|
||||||
|
const { error, data } = await useAPI('load-all-articles/', {method: "GET"});
|
||||||
|
|
||||||
|
if ( data.value ){
|
||||||
|
articles.value = data.value as Article[];
|
||||||
|
}
|
||||||
|
else if (error.value) {
|
||||||
|
console.error("Error loading articles:", error.value);
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<v-parallax
|
<v-parallax
|
||||||
src="https://danceostrava.cz/wp-content/uploads/2021/10/IMG_5203-scaled.jpg"
|
src="public/dark-dance.jpg"
|
||||||
>
|
>
|
||||||
<div class="d-flex flex-column fill-height justify-center">
|
<div class="d-flex flex-column fill-height justify-center">
|
||||||
<h1 class="text-white">
|
<h1 class="text-white">
|
||||||
|
@ -11,13 +11,12 @@
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
</v-parallax>
|
</v-parallax>
|
||||||
<calendar/>
|
|
||||||
<news/>
|
<news/>
|
||||||
<trainers/>
|
|
||||||
<about/>
|
<about/>
|
||||||
<advantages/>
|
|
||||||
<courses/>
|
<courses/>
|
||||||
<contact-us/>
|
<trainers/>
|
||||||
|
<advantages/>
|
||||||
|
<history/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|
37
services/frontend/pages/kurzy.vue
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
<template>
|
||||||
|
<h1 id="courses">Kurzy</h1>
|
||||||
|
<h2>Vyberte, co Vám nejlépe vyhovuje</h2>
|
||||||
|
|
||||||
|
<v-row>
|
||||||
|
<v-col
|
||||||
|
cols="12"
|
||||||
|
md="4"
|
||||||
|
v-for="(course, index) in courses"
|
||||||
|
:key="index"
|
||||||
|
>
|
||||||
|
<v-card class="pricing-box">
|
||||||
|
<h3>{{ course.name }}</h3>
|
||||||
|
<v-card-subtitle><div class="pricing__subtitle">{{ course.time }}</div></v-card-subtitle>
|
||||||
|
<v-card-title><div class="pricing__price">{{ course.price }}</div></v-card-title>
|
||||||
|
<v-card-text v-if="course.desc"><div class="pricing__subtitle">{{ course.desc }}</div></v-card-text>
|
||||||
|
<v-btn class="show_more"><v-icon icon="mdi-chevron-down"/>Kontaktujte nás<v-icon icon="mdi-chevron-down"/></v-btn>
|
||||||
|
</v-card>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
<calendar/>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import './assets/css/main.css'
|
||||||
|
|
||||||
|
// TODO: vyskakovací okno s kontaktním formulářem po rozkliku :)
|
||||||
|
|
||||||
|
const courses = [
|
||||||
|
{name: "Sportovní taneční klub", time: "", price: "", desc: "Připojte se k našemu tanečnímu klubu a rozvíjejte své taneční dovednosti v přátelském prostředí. Nabízíme různé styly tance pro všechny úrovně."},
|
||||||
|
{name: "Svatební tance", time: "", price: "", desc: "Udělejte svůj první tanec nezapomenutelným. Pomůžeme Vám vytvořit choreografii na míru, která bude odrážet Váš jedinečný styl."},
|
||||||
|
{name: "Příprava na plesovou sezónu", time: "", price: "", desc: "Chcete zazářit na plese? Připravíme Vás na plesovou sezónu a naučíme Vás elegantní taneční kroky a etiketu."},
|
||||||
|
{name: "Individuální taneční kurzy", time: "", price: "", desc: "Učte se tančit vlastním tempem s individuálním přístupem. Naši zkušení lektoři se zaměří na Vaše potřeby a pomohou Vám dosáhnout Vašich tanečních cílů."},
|
||||||
|
{name: "Individuální lekce", time: "", price: "", desc: "Zlepšete své taneční dovednosti s intenzivními individuálními lekcemi. Zaměřte se na konkrétní taneční techniky nebo styly, které Vás zajímají."},
|
||||||
|
{name: "Pronájem sálu", time: "", price: "", desc: "Hledáte ideální prostor pro tanec nebo jinou aktivitu? Náš taneční sál je k dispozici k pronájmu pro Vaše akce."},
|
||||||
|
]
|
||||||
|
|
||||||
|
</script>
|
|
@ -58,6 +58,13 @@ export default defineNuxtPlugin((app) => {
|
||||||
},
|
},
|
||||||
locale: {
|
locale: {
|
||||||
locale: 'cs',
|
locale: 'cs',
|
||||||
|
messages: {
|
||||||
|
cs: {
|
||||||
|
calendar: {
|
||||||
|
today: "dnes",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
date: {
|
date: {
|
||||||
locale: {
|
locale: {
|
||||||
|
|
Before Width: | Height: | Size: 100 KiB |
BIN
services/frontend/public/dark-dance.jpg
Normal file
After Width: | Height: | Size: 108 KiB |
BIN
services/frontend/public/img/black-pink.jpg
Normal file
After Width: | Height: | Size: 127 KiB |
BIN
services/frontend/public/img/dancing.jpg
Normal file
After Width: | Height: | Size: 74 KiB |
BIN
services/frontend/public/img/image1_0.jpg
Normal file
After Width: | Height: | Size: 127 KiB |
BIN
services/frontend/public/img/tko1.webp
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
services/frontend/public/logo.png
Normal file
After Width: | Height: | Size: 111 KiB |
BIN
services/frontend/public/logo.webp
Normal file
After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 110 KiB |
BIN
services/frontend/public/trainers/img.png
Normal file
After Width: | Height: | Size: 233 KiB |