reverted to old web configuration on main branch
0
home/__init__.py
Normal file
9
home/admin.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
from .models import AnonMessage
|
||||
|
||||
class AnonMessageUI(admin.ModelAdmin):
|
||||
search_fields = ['time']
|
||||
|
||||
admin.site.register(AnonMessage, AnonMessageUI)
|
||||
6
home/apps.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class HomeConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'home'
|
||||
215
home/consumers.py
Normal file
@@ -0,0 +1,215 @@
|
||||
import json
|
||||
from channels.generic.websocket import AsyncWebsocketConsumer
|
||||
from channels.db import database_sync_to_async
|
||||
from datetime import datetime
|
||||
from django.utils import timezone
|
||||
|
||||
import uuid
|
||||
|
||||
from .models import AnonMessage
|
||||
|
||||
|
||||
class AnonymChatConsumer(AsyncWebsocketConsumer):
|
||||
|
||||
async def connect(self):
|
||||
# Generate a unique user ID for this WebSocket connection
|
||||
self.user_id = str(uuid.uuid4())
|
||||
self.room_name = "global_room"
|
||||
|
||||
# Add the user to the global room group
|
||||
await self.channel_layer.group_add(self.room_name, self.channel_name)
|
||||
|
||||
# Accept the WebSocket connection
|
||||
await self.accept()
|
||||
|
||||
async def disconnect(self, code):
|
||||
# Remove the user from the global room group when disconnected
|
||||
await self.channel_layer.group_discard(self.room_name, self.channel_name)
|
||||
await self.close(code)
|
||||
|
||||
async def receive(self, text_data):
|
||||
# Parse the received JSON message
|
||||
data_json = json.loads(text_data)
|
||||
|
||||
# Include the user ID and time for broadcasting
|
||||
event = {
|
||||
"type": "send_message",
|
||||
"message": data_json["message"],
|
||||
"user_id": self.user_id, # Attach the user ID to the event
|
||||
}
|
||||
|
||||
# Broadcast the message to the global room group
|
||||
await self.channel_layer.group_send(self.room_name, event)
|
||||
|
||||
async def send_message(self, event):
|
||||
# Check if the sender's ID is the same as the current user to avoid sending back the message
|
||||
message_time = await self.create_message(event["message"])
|
||||
print({"time": message_time.strftime("%b. %d, %Y, %I:%M %p").lower()})
|
||||
|
||||
if event["user_id"] != self.user_id:
|
||||
# Format the message with time and send to WebSocket clients
|
||||
response = {
|
||||
"message": event["message"],
|
||||
"time": message_time.strftime("%b. %d, %Y, %H:%M")
|
||||
}
|
||||
|
||||
await self.send(text_data=json.dumps(response))
|
||||
|
||||
@database_sync_to_async
|
||||
def create_message(self, text):
|
||||
# Create a new message in the database and return its timestamp
|
||||
return AnonMessage.objects.create(text=text).time
|
||||
|
||||
|
||||
|
||||
user_counter = 0
|
||||
peers = {}
|
||||
|
||||
class AnonymVoiceConsumer(AsyncWebsocketConsumer):
|
||||
async def connect(self):
|
||||
self.group_name = 'voice_room_group'
|
||||
self.peer_id = None
|
||||
|
||||
await self.channel_layer.group_add(
|
||||
self.group_name,
|
||||
self.channel_name
|
||||
)
|
||||
|
||||
await self.accept()
|
||||
|
||||
async def disconnect(self, close_code):
|
||||
global user_counter, peers
|
||||
|
||||
await self.channel_layer.group_discard(
|
||||
self.group_name,
|
||||
self.channel_name
|
||||
)
|
||||
|
||||
if self.peer_id in peers:
|
||||
del peers[self.peer_id]
|
||||
user_counter -= 1
|
||||
await self.send_user_count()
|
||||
|
||||
async def receive(self, text_data):
|
||||
global user_counter, peers
|
||||
|
||||
data_json = json.loads(text_data)
|
||||
if data_json['type'] == "connected_user":
|
||||
self.peer_id = data_json['peer_id']
|
||||
peers[self.peer_id] = self.channel_name
|
||||
user_counter += 1
|
||||
await self.send_user_count()
|
||||
await self.send_peer_id_to_others(self.peer_id)
|
||||
elif data_json['type'] == "disconnecting_user":
|
||||
if self.peer_id in peers:
|
||||
del peers[self.peer_id]
|
||||
user_counter -= 1
|
||||
await self.send_user_count()
|
||||
elif data_json['type'] == "request_user_count":
|
||||
await self.send_user_count()
|
||||
|
||||
async def send_user_count(self):
|
||||
await self.channel_layer.group_send(
|
||||
self.group_name, {
|
||||
'type': 'group_announcement',
|
||||
'users_count': user_counter,
|
||||
}
|
||||
)
|
||||
|
||||
async def send_peer_id_to_others(self, peer_id):
|
||||
await self.channel_layer.group_send(
|
||||
self.group_name, {
|
||||
'type': 'peer_id_message',
|
||||
'peer_id': peer_id,
|
||||
'exclude': self.channel_name # Exclude the sender
|
||||
}
|
||||
)
|
||||
|
||||
async def group_announcement(self, event):
|
||||
users_count = event['users_count']
|
||||
await self.send(text_data=json.dumps({
|
||||
'type': 'user_count_message',
|
||||
'users_count': users_count
|
||||
}))
|
||||
|
||||
async def peer_id_message(self, event):
|
||||
if self.channel_name != event.get('exclude'):
|
||||
await self.send(text_data=json.dumps({
|
||||
'type': 'peer_id_message',
|
||||
'peer_id': event['peer_id']
|
||||
}))
|
||||
|
||||
|
||||
class DirectVoiceConsumer(AsyncWebsocketConsumer):
|
||||
async def connect(self):
|
||||
self.group_name = "id_pool"
|
||||
self.peer_id = None
|
||||
|
||||
await self.channel_layer.group_add(
|
||||
self.group_name,
|
||||
self.channel_name
|
||||
)
|
||||
|
||||
await self.accept()
|
||||
|
||||
async def disconnect(self, close_code):
|
||||
global user_counter, peers
|
||||
|
||||
await self.channel_layer.group_discard(
|
||||
self.group_name,
|
||||
self.channel_name
|
||||
)
|
||||
|
||||
if self.peer_id in peers:
|
||||
del peers[self.peer_id]
|
||||
user_counter -= 1
|
||||
await self.send_user_count()
|
||||
|
||||
async def receive(self, text_data):
|
||||
global user_counter, peers
|
||||
|
||||
data_json = json.loads(text_data)
|
||||
if data_json['type'] == "connected_user":
|
||||
self.peer_id = data_json['peer_id']
|
||||
peers[self.peer_id] = self.channel_name
|
||||
user_counter += 1
|
||||
await self.send_user_count()
|
||||
await self.send_peer_id_to_others(self.peer_id)
|
||||
elif data_json['type'] == "disconnecting_user":
|
||||
if self.peer_id in peers:
|
||||
del peers[self.peer_id]
|
||||
user_counter -= 1
|
||||
await self.send_user_count()
|
||||
elif data_json['type'] == "request_user_count":
|
||||
await self.send_user_count()
|
||||
|
||||
async def send_user_count(self):
|
||||
await self.channel_layer.group_send(
|
||||
self.group_name, {
|
||||
'type': 'group_announcement',
|
||||
'users_count': user_counter,
|
||||
}
|
||||
)
|
||||
|
||||
async def send_peer_id_to_others(self, peer_id):
|
||||
await self.channel_layer.group_send(
|
||||
self.group_name, {
|
||||
'type': 'peer_id_message',
|
||||
'peer_id': peer_id,
|
||||
'exclude': self.channel_name # Exclude the sender
|
||||
}
|
||||
)
|
||||
|
||||
async def group_announcement(self, event):
|
||||
users_count = event['users_count']
|
||||
await self.send(text_data=json.dumps({
|
||||
'type': 'user_count_message',
|
||||
'users_count': users_count
|
||||
}))
|
||||
|
||||
async def peer_id_message(self, event):
|
||||
if self.channel_name != event.get('exclude'):
|
||||
await self.send(text_data=json.dumps({
|
||||
'type': 'peer_id_message',
|
||||
'peer_id': event['peer_id']
|
||||
}))
|
||||
24
home/forms.py
Normal file
@@ -0,0 +1,24 @@
|
||||
from django import forms
|
||||
|
||||
class ContactMe(forms.Form):
|
||||
customer_name = forms.CharField(
|
||||
label="Your name",
|
||||
max_length=100,
|
||||
widget=forms.TextInput(attrs={'placeholder': 'Enter your name'})
|
||||
)
|
||||
customer_email = forms.EmailField(
|
||||
label="Your email",
|
||||
widget=forms.EmailInput(
|
||||
attrs={'placeholder': 'Enter email'}
|
||||
)
|
||||
)
|
||||
message = forms.CharField(
|
||||
label="Message",
|
||||
widget=forms.Textarea(
|
||||
attrs={
|
||||
'rows': 4,
|
||||
'cols': 50,
|
||||
'placeholder': 'Type your message here...'
|
||||
}
|
||||
)
|
||||
)
|
||||
23
home/models.py
Normal file
@@ -0,0 +1,23 @@
|
||||
from django.db import models
|
||||
|
||||
class AnonMessage(models.Model):
|
||||
text = models.TextField(null=False)
|
||||
time = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.text[:20]}... - {self.time}"
|
||||
|
||||
@classmethod
|
||||
def get_last_messages(cls, count=10, reverse=False):
|
||||
"""
|
||||
Fetch the last `count` messages with optional reversal.
|
||||
|
||||
:param count: Number of messages to fetch.
|
||||
:param reverse: If True, return messages in ascending order (oldest to newest).
|
||||
If False, return messages in descending order (newest to oldest).
|
||||
"""
|
||||
queryset = cls.objects.order_by('-time')[:count]
|
||||
return queryset[::-1] if reverse else queryset
|
||||
|
||||
class TestMedia(models.Model):
|
||||
file = models.FileField()
|
||||
10
home/routing.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from django.urls import re_path, path
|
||||
|
||||
from . import consumers
|
||||
|
||||
|
||||
|
||||
websocket_urlpatterns = [
|
||||
re_path("ws/anonChat/", consumers.AnonymChatConsumer.as_asgi()),
|
||||
re_path("ws/AnonVoice/", consumers.AnonymVoiceConsumer.as_asgi()),
|
||||
]
|
||||
11
home/sitemaps.py
Normal file
@@ -0,0 +1,11 @@
|
||||
# in sitemaps.py
|
||||
|
||||
from django.contrib.sitemaps import Sitemap
|
||||
# from .models import #modely
|
||||
|
||||
'''class HomeSitemap(Sitemap):
|
||||
def items(self):
|
||||
return UserProfile.objects.all()
|
||||
|
||||
def location(self, item):
|
||||
return item.get_absolute_url()'''
|
||||
115
home/static/home/css/components/carousel.css
Normal file
@@ -0,0 +1,115 @@
|
||||
.carousel{
|
||||
display: none !important; /*TEMP TURNED OFF*/
|
||||
|
||||
height: 25em;
|
||||
width: 100%;
|
||||
margin-bottom: 1em;
|
||||
overflow-x: hidden;
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.carousel-inner{
|
||||
height: 100%;
|
||||
/* min-width: 400%; */
|
||||
display: flex;
|
||||
transition: all ease .5s;
|
||||
}
|
||||
|
||||
.carousel-item{
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.carousel-item h1{
|
||||
position: relative;
|
||||
color: white;
|
||||
bottom: 1.5em;
|
||||
}
|
||||
.carousel-controls .prev{
|
||||
display: inline-block;
|
||||
height: 3em;
|
||||
width: 3em;
|
||||
position: absolute;
|
||||
left: 12px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
background-image: url('/static/home/img/carousel/prev.svg');
|
||||
background-position: center;
|
||||
background-size: auto 100%;
|
||||
background-repeat: no-repeat;
|
||||
cursor: pointer;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.carousel-controls .next{
|
||||
display: inline-block;
|
||||
height: 3em;
|
||||
width: 3em;
|
||||
position: absolute;
|
||||
right: 12px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
background-image: url('/static/home/img/carousel/next.svg');
|
||||
background-position: center;
|
||||
background-size: auto 100%;
|
||||
background-repeat: no-repeat;
|
||||
cursor: pointer;
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
.prev:hover, .next:hover{
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.carousel-indicators{
|
||||
position: absolute;
|
||||
bottom: 4em;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.carousel-indicators span{
|
||||
display: inline-block;
|
||||
background-color: white;
|
||||
width: 30px;
|
||||
height: 4px;
|
||||
border-radius: 2px;
|
||||
opacity: .5;
|
||||
cursor: pointer;
|
||||
margin: 3px;
|
||||
}
|
||||
|
||||
.carousel-indicators span.active{
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
|
||||
/*ODKAZY NA FOTKY JSOU PŘÍMO V HTML PROTOŽE CHCI PARSNOUT STATIC TAG */
|
||||
|
||||
|
||||
@media only screen and (min-width: 991px){
|
||||
.prev, .next{
|
||||
height: 1.5em !important;
|
||||
width: 1.5em !important;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@media only screen and (max-width: 990px){
|
||||
.carousel{
|
||||
height: 100vh;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
}
|
||||
88
home/static/home/css/components/demo/chat.css
Normal file
@@ -0,0 +1,88 @@
|
||||
.chat {
|
||||
background-color: var(--c-boxes);
|
||||
color: var(--c-text);
|
||||
padding: 1em;
|
||||
height: 28em;
|
||||
border-radius: 1em;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.chat .title-bar {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
.chat .messages {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow-y: scroll;
|
||||
max-height: 19.5em;
|
||||
}
|
||||
|
||||
.chat .messages div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.chat .messages div sub {
|
||||
font-size: 0.8em;
|
||||
color: rgb(176, 176, 176);
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
.chat .messages div p {
|
||||
padding: 0.5em;
|
||||
width: 95%;
|
||||
margin-bottom: 0.5em;
|
||||
margin-left: 0.5em;
|
||||
margin-right: 0.5em;
|
||||
color: black;
|
||||
background-color: rgb(156, 156, 156);
|
||||
}
|
||||
|
||||
.messages::-webkit-scrollbar {
|
||||
background-color: var(--c-boxes);
|
||||
width: 0.2em;
|
||||
}
|
||||
|
||||
/* Track */
|
||||
.messages::-webkit-scrollbar-track {
|
||||
box-shadow: inset 0 0 5px var(--c-lines);
|
||||
border-radius: 0.2em;
|
||||
}
|
||||
|
||||
/* Handle */
|
||||
.messages::-webkit-scrollbar-thumb {
|
||||
background: var(--c-text);
|
||||
border-radius: 0.2em;
|
||||
}
|
||||
|
||||
/* Handle on hover */
|
||||
.messages::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--c-background-light);
|
||||
}
|
||||
|
||||
.chat .send-box {
|
||||
margin-top: 1em;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.chat .send-box button {
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
font-size: 1.5em;
|
||||
margin: 0 0.5em;
|
||||
}
|
||||
.chat .send-box input{
|
||||
padding: 0.5em;
|
||||
width: -webkit-fill-available;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 990px) {
|
||||
.chat {
|
||||
margin: 0;
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
63
home/static/home/css/components/demo/direct-voice-chat.css
Normal file
@@ -0,0 +1,63 @@
|
||||
.direct-voice-chat{
|
||||
background-color: var(--c-boxes);
|
||||
color: var(--c-text);
|
||||
padding: 1em;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.direct-voice-chat .title-bar{
|
||||
font-size: 2em;
|
||||
}
|
||||
.direct-voice-chat .info{
|
||||
padding: 1em;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.direct-voice-chat .connection{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding: 1em;
|
||||
}
|
||||
.direct-voice-chat .connection input{
|
||||
padding: 0.5em;
|
||||
width: -webkit-fill-available;
|
||||
}
|
||||
.direct-voice-chat .connection button{
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
font-size: 1.5em;
|
||||
margin: 0 0.5em;
|
||||
}
|
||||
.direct-voice-chat .incoming-call-container{
|
||||
padding: 1em;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.incoming-call-container #direct-accept-call-btn{
|
||||
color: white;
|
||||
background-color: green;
|
||||
clip-path: circle(50% at 50% 50%);
|
||||
padding: 1em;
|
||||
}
|
||||
.incoming-call-container #direct-deny-call-btn{
|
||||
color: white;
|
||||
background-color: rgb(148, 0, 0);
|
||||
clip-path: circle(50% at 50% 50%);
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.direct-voice-chat .window .window-body:first-child{
|
||||
margin-top: 1em;
|
||||
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 990px) {
|
||||
|
||||
}
|
||||
104
home/static/home/css/components/demo/global-voice-chat.css
Normal file
@@ -0,0 +1,104 @@
|
||||
.global-voice-chat {
|
||||
position: relative;
|
||||
background-color: var(--c-boxes);
|
||||
color: var(--c-text);
|
||||
padding: 1em;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.global-voice-chat .title-bar {
|
||||
margin: auto;
|
||||
font-size: 2em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.global-voice-chat .fa-circle {
|
||||
color: #ddd;
|
||||
text-shadow: 0 0 4px black;
|
||||
}
|
||||
.global-voice-chat .info{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
}
|
||||
.info div:nth-child(2) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.7em;
|
||||
}
|
||||
.info button{
|
||||
margin: 0.5em auto;
|
||||
padding: 0.5em;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
font: initial;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
.info i{
|
||||
font-size: 1.8em;
|
||||
padding-right: 0.5em;
|
||||
}
|
||||
.global-voice-chat .controls{
|
||||
margin-top: 1em;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
}
|
||||
.controls button{
|
||||
border-radius: 50%;
|
||||
border: none;
|
||||
|
||||
padding: 0.5em 0.55em;
|
||||
font: initial;
|
||||
font-size: 1.5em;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
#global-disconnect-btn{
|
||||
padding: 0.5em 0.4em;
|
||||
}
|
||||
|
||||
.active-call::after {
|
||||
position: absolute;
|
||||
content: "";
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: -1;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
transform: scale(1.2) translateZ(0);
|
||||
filter: blur(15px);
|
||||
background: rgb(33, 105, 42);
|
||||
background: -moz-linear-gradient(90deg, rgba(33, 105, 42, 1) 0%, rgba(120, 253, 29, 1) 50%, rgba(69, 252, 155, 1) 100%);
|
||||
background: -webkit-linear-gradient(90deg, rgba(33, 105, 42, 1) 0%, rgba(120, 253, 29, 1) 50%, rgba(69, 252, 155, 1) 100%);
|
||||
background: linear-gradient(90deg, rgba(33, 105, 42, 1) 0%, rgba(120, 253, 29, 1) 50%, rgba(69, 252, 155, 1) 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#21692a", endColorstr="#45fc9b", GradientType=1);
|
||||
background-size: 100% 100%;
|
||||
animation: animateGlow 1.25s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes animateGlow {
|
||||
0% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
|
||||
100% {
|
||||
background-position: 200% 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.global-voice-chat .online {
|
||||
color: #a9f634 !important;
|
||||
}
|
||||
|
||||
.global-voice-chat .fa-phone {
|
||||
color: #008000;
|
||||
}
|
||||
|
||||
.global-voice-chat .fa-phone-slash {
|
||||
color: #a80000;
|
||||
}
|
||||
103
home/static/home/css/components/drone.css
Normal file
@@ -0,0 +1,103 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap');
|
||||
|
||||
|
||||
|
||||
|
||||
.drone{
|
||||
margin-top: -4em;
|
||||
font-style: normal;
|
||||
|
||||
width: 100%;
|
||||
position: relative;
|
||||
color: white;
|
||||
}
|
||||
|
||||
|
||||
.drone .video-background {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
object-fit: cover;
|
||||
z-index: -1;
|
||||
|
||||
clip-path: polygon(0 3%, 15% 0, 30% 7%, 42% 3%, 61% 1%, 82% 5%, 100% 1%, 100% 94%, 82% 100%, 65% 96%, 47% 99%, 30% 90%, 14% 98%, 0 94%);
|
||||
}
|
||||
|
||||
|
||||
.drone article{
|
||||
padding: 5em;
|
||||
|
||||
display: flex;
|
||||
|
||||
border-radius: 2em;
|
||||
padding: 3em;
|
||||
gap: 2em;
|
||||
|
||||
position: relative;
|
||||
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
.drone article header h1{
|
||||
font-size: 4em;
|
||||
|
||||
font-weight: 300;
|
||||
}
|
||||
.drone article header{
|
||||
flex: 1;
|
||||
}
|
||||
.drone article main{
|
||||
width: 90%;
|
||||
display: flex;
|
||||
font-size: 1em;
|
||||
/* width: 60%; */
|
||||
flex: 2;
|
||||
flex-direction: row;
|
||||
|
||||
font-weight: 400;
|
||||
|
||||
gap: 2em;
|
||||
/* flex-wrap: wrap; */
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
.drone a{
|
||||
color: white;
|
||||
}
|
||||
.drone article div{
|
||||
display: flex;
|
||||
flex: 1;
|
||||
font-size: 1.25em;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
|
||||
@media only screen and (max-width: 990px) {
|
||||
.drone article header h1{
|
||||
font-size: 2.3em;
|
||||
|
||||
font-weight: 200;
|
||||
}
|
||||
.drone article header{
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.drone article main{
|
||||
flex-direction: column;
|
||||
font-size: 1em;
|
||||
}
|
||||
.drone article{
|
||||
height: auto;
|
||||
}
|
||||
.drone article div{
|
||||
margin: 2em;
|
||||
text-align: center;
|
||||
}
|
||||
.drone video{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
140
home/static/home/css/components/global/contact-me.css
Normal file
@@ -0,0 +1,140 @@
|
||||
.contact-me {
|
||||
margin: 5em auto;
|
||||
position: relative;
|
||||
|
||||
aspect-ratio: 16 / 9;
|
||||
|
||||
background-color: #c8c8c8;
|
||||
max-width: 100vw;
|
||||
}
|
||||
.contact-me + .mail-box{
|
||||
|
||||
}
|
||||
|
||||
.contact-me .opening {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
z-index: 2;
|
||||
transform-origin: top;
|
||||
|
||||
padding-top: 4em;
|
||||
|
||||
clip-path: polygon(0 0, 100% 0, 50% 50%);
|
||||
background-color: #d2d2d2;
|
||||
|
||||
transition: all 1s ease;
|
||||
|
||||
text-align: center;
|
||||
}
|
||||
.rotate-opening{
|
||||
background-color: #c8c8c8;
|
||||
transform: rotateX(180deg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
.contact-me .content {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
transition: all 1s ease-out;
|
||||
}
|
||||
.content-moveup{
|
||||
transform: translateY(-70%);
|
||||
}
|
||||
.content-moveup-index {
|
||||
z-index: 2 !important;
|
||||
}
|
||||
|
||||
.contact-me .content form{
|
||||
width: 80%;
|
||||
display: flex;
|
||||
gap: 1em;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
margin: auto;
|
||||
background-color: #deefff;
|
||||
padding: 1em;
|
||||
border: 0.5em dashed #88d4ed;
|
||||
border-radius: 0.25em;
|
||||
}
|
||||
.contact-me .content form div{
|
||||
width: -webkit-fill-available;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.contact-me .content form input[type=submit]{
|
||||
margin: auto;
|
||||
border: none;
|
||||
background: #4ca4d5;
|
||||
color: #ffffff;
|
||||
padding: 1em 1.5em;
|
||||
cursor: pointer;
|
||||
border-radius: 1em;
|
||||
}
|
||||
|
||||
.contact-me .content form input[type=text],
|
||||
.contact-me .content form input[type=email],
|
||||
.contact-me .content form textarea{
|
||||
background-color: #bfe8ff;
|
||||
border: none;
|
||||
border-bottom: 0.15em solid #064c7d;
|
||||
padding: 0.5em;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
.contact-me .cover {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 2;
|
||||
clip-path: polygon(0 0, 50% 50%, 100% 0, 100% 100%, 0 100%);
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
.contact-me .triangle{
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
z-index: 3;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
clip-path: polygon(100% 0, 0 100%, 100% 100%);
|
||||
background-color: rgb(255 255 255);
|
||||
}
|
||||
|
||||
@keyframes shake {
|
||||
0% { transform: translateX(0); }
|
||||
25% { transform: translateX(-2px) rotate(-8deg); }
|
||||
50% { transform: translateX(2px) rotate(4deg); }
|
||||
75% { transform: translateX(-1px) rotate(-2deg); }
|
||||
100% { transform: translateX(0); }
|
||||
}
|
||||
|
||||
|
||||
.contact-me .opening i {
|
||||
color: #797979;
|
||||
font-size: 5em;
|
||||
display: inline-block;
|
||||
animation: 0.4s ease-in-out 2s infinite normal none running shake;
|
||||
animation-delay: 2s;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@media only screen and (max-width: 990px){
|
||||
.contact-me{
|
||||
aspect-ratio: unset;
|
||||
margin-top: 7ch;
|
||||
}
|
||||
}
|
||||
192
home/static/home/css/components/introduction.css
Normal file
@@ -0,0 +1,192 @@
|
||||
.introduction {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
color: var(--c-text);
|
||||
|
||||
padding-bottom: 10em;
|
||||
margin-top: 6em;
|
||||
|
||||
width: 100%;
|
||||
position: relative;
|
||||
top:0;
|
||||
|
||||
/* gap: 4em;*/
|
||||
}
|
||||
.introduction h1{
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
.introduction article {
|
||||
/*background-color: cadetblue;*/
|
||||
|
||||
padding: 2em;
|
||||
border-radius: 1em;
|
||||
}
|
||||
|
||||
.introduction article header {}
|
||||
|
||||
.introduction article:nth-child(1) {
|
||||
width: 100%;
|
||||
/* transform: rotate(5deg); */
|
||||
align-self: center;
|
||||
text-align: center;
|
||||
font-size: 2em;
|
||||
}
|
||||
/*
|
||||
.introduction article:nth-child(2) {
|
||||
width: 50%;
|
||||
transform: rotate(3deg);
|
||||
align-self: flex-end;
|
||||
}
|
||||
|
||||
.introduction article:nth-child(3) {
|
||||
width: 50%;
|
||||
transform: rotate(-2deg);
|
||||
align-self: flex-start;
|
||||
}*/
|
||||
|
||||
|
||||
|
||||
|
||||
.animation-introduction{
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
z-index: -2;
|
||||
}
|
||||
|
||||
.animation-introduction ul{
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
/*overflow: hidden; ZAPNOUT KDYŽ NECHCEŠ ANIMACI PŘECHÁZET DO OSTATNÍCH DIVŮ*/
|
||||
}
|
||||
|
||||
.animation-introduction ul li{
|
||||
position: absolute;
|
||||
display: block;
|
||||
list-style: none;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: rgba(255, 255, 255, 35%);
|
||||
animation: animate 4s linear infinite;
|
||||
bottom: -150px;
|
||||
|
||||
}
|
||||
|
||||
.animation-introduction ul li:nth-child(1){
|
||||
left: 25%;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
animation-delay: 0s;
|
||||
}
|
||||
|
||||
|
||||
.animation-introduction ul li:nth-child(2){
|
||||
left: 10%;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
animation-delay: 2s;
|
||||
animation-duration: 12s;
|
||||
}
|
||||
|
||||
.animation-introduction ul li:nth-child(3){
|
||||
left: 70%;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
animation-delay: 4s;
|
||||
}
|
||||
|
||||
.animation-introduction ul li:nth-child(4){
|
||||
left: 40%;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
animation-delay: 0s;
|
||||
animation-duration: 18s;
|
||||
}
|
||||
|
||||
.animation-introduction ul li:nth-child(5){
|
||||
left: 65%;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
animation-delay: 0s;
|
||||
}
|
||||
|
||||
.animation-introduction ul li:nth-child(6){
|
||||
left: 75%;
|
||||
width: 110px;
|
||||
height: 110px;
|
||||
animation-delay: 3s;
|
||||
}
|
||||
|
||||
.animation-introduction ul li:nth-child(7){
|
||||
left: 35%;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
animation-delay: 7s;
|
||||
}
|
||||
|
||||
.animation-introduction ul li:nth-child(8){
|
||||
left: 50%;
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
animation-delay: 15s;
|
||||
animation-duration: 45s;
|
||||
}
|
||||
|
||||
.animation-introduction ul li:nth-child(9){
|
||||
left: 20%;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
animation-delay: 2s;
|
||||
animation-duration: 35s;
|
||||
}
|
||||
|
||||
.animation-introduction ul li:nth-child(10){
|
||||
left: 85%;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
animation-delay: 0s;
|
||||
animation-duration: 11s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@keyframes animate {
|
||||
|
||||
0%{
|
||||
transform: translateY(0) rotate(0deg);
|
||||
opacity: 1;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
100%{
|
||||
transform: translateY(-1000px) rotate(720deg);
|
||||
opacity: 0;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@media only screen and (max-width: 990px) {
|
||||
.animation-introduction ul li:nth-child(6){
|
||||
left: 67%;
|
||||
}
|
||||
.animation-introduction ul li:nth-child(10) {
|
||||
left: 60%;
|
||||
}
|
||||
.introduction {
|
||||
margin: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.introduction article {
|
||||
width: auto !important;
|
||||
transform: none !important;
|
||||
align-self: none !important;
|
||||
}
|
||||
}
|
||||
155
home/static/home/css/components/portfolio.css
Normal file
@@ -0,0 +1,155 @@
|
||||
.portfolio {
|
||||
margin: auto;
|
||||
margin-top: 10em;
|
||||
width: 80%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-content: center;
|
||||
color: white;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.portfolio div .door {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background-color: #c2a67d;
|
||||
|
||||
border-radius: 1em;
|
||||
|
||||
transform-origin: bottom;
|
||||
transition: transform 0.5s ease-in-out;
|
||||
|
||||
z-index: 3;
|
||||
|
||||
}
|
||||
|
||||
@keyframes shake {
|
||||
0% { transform: translateX(0); }
|
||||
25% { transform: translateX(-2px) rotate(-8deg); }
|
||||
50% { transform: translateX(2px) rotate(4deg); }
|
||||
75% { transform: translateX(-1px) rotate(-2deg); }
|
||||
100% { transform: translateX(0); }
|
||||
}
|
||||
|
||||
.door i{
|
||||
color: #5e5747;
|
||||
font-size: 5em;
|
||||
display: inline-block;
|
||||
animation: shake 0.4s ease-in-out infinite;
|
||||
animation-delay: 2s;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
|
||||
.portfolio .door-open{
|
||||
transform: rotateX(180deg);
|
||||
}
|
||||
|
||||
.portfolio>header {
|
||||
width: fit-content;
|
||||
position: absolute;
|
||||
z-index: 5;
|
||||
top: -4.7em;
|
||||
left: 0;
|
||||
padding: 1em 3em;
|
||||
padding-bottom: 0;
|
||||
background-color: #cdc19c;
|
||||
color: #5e5747;
|
||||
border-top-left-radius: 1em;
|
||||
border-top-right-radius: 1em;
|
||||
}
|
||||
|
||||
.portfolio>header h1 {
|
||||
font-size: 2.5em;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.portfolio>header i {
|
||||
font-size: 6em;
|
||||
}
|
||||
|
||||
.portfolio article{
|
||||
position: relative;
|
||||
}
|
||||
.portfolio article::after{
|
||||
clip-path: polygon(0% 0%, 11% 12.5%, 0% 25%, 11% 37.5%, 0% 50%, 11% 62.5%, 0% 75%, 11% 87.5%, 0% 100%, 100% 100%, 84% 87.5%, 98% 75%, 86% 62.5%, 100% 50%, 86% 37.5%, 100% 25%, 93% 12.5%, 100% 0%);
|
||||
content: "";
|
||||
bottom: 0;
|
||||
right: -2em;
|
||||
|
||||
height: 2em;
|
||||
width: 6em;
|
||||
transform: rotate(-45deg);
|
||||
|
||||
position: absolute;
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
.portfolio article::before{
|
||||
clip-path: polygon(0% 0%, 11% 12.5%, 0% 25%, 11% 37.5%, 0% 50%, 11% 62.5%, 0% 75%, 11% 87.5%, 0% 100%, 100% 100%, 84% 87.5%, 98% 75%, 86% 62.5%, 100% 50%, 86% 37.5%, 100% 25%, 93% 12.5%, 100% 0%);
|
||||
content: "";
|
||||
top: 0;
|
||||
left: -2em;
|
||||
|
||||
height: 2em;
|
||||
width: 6em;
|
||||
transform: rotate(-45deg);
|
||||
|
||||
position: absolute;
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.portfolio article header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
|
||||
.portfolio div {
|
||||
padding: 3em;
|
||||
background-color: #cdc19c;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
|
||||
gap: 5em;
|
||||
|
||||
border-radius: 1em;
|
||||
border-top-left-radius: 0;
|
||||
}
|
||||
|
||||
.portfolio div article {
|
||||
display: flex;
|
||||
border-radius: 0em;
|
||||
background-color: #9c885c;
|
||||
width: 30%;
|
||||
text-align: center;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.portfolio div article header a img {
|
||||
padding: 2em 0;
|
||||
width: 80%;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@media only screen and (max-width: 990px) {
|
||||
.portfolio div{
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.portfolio div article{
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
78
home/static/home/css/components/services.css
Normal file
@@ -0,0 +1,78 @@
|
||||
.services {
|
||||
margin-top: 4em;
|
||||
}
|
||||
|
||||
.services article {
|
||||
margin: 2rem auto;
|
||||
padding: 2em;
|
||||
width: 30%;
|
||||
|
||||
|
||||
border: 1px solid #d0d7de;
|
||||
/* Jemná šedá barva */
|
||||
border-radius: 6px;
|
||||
/* Kulaté rohy */
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
/* Decentní stín */
|
||||
padding: 16px;
|
||||
/* Vnitřní odsazení */
|
||||
background-color: #f6f8fa;
|
||||
/* Bílé pozadí */
|
||||
}
|
||||
|
||||
.services>header {
|
||||
color: white;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.services>header h1 {
|
||||
font-size: 2.5em;
|
||||
}
|
||||
|
||||
.services>header i {
|
||||
font-size: 6em;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.services article header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.services article header h1 {
|
||||
font-size: 1.25em;
|
||||
}
|
||||
|
||||
.services article header i {
|
||||
font-size: 3em;
|
||||
}
|
||||
|
||||
.services div {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.services div article main {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@media only screen and (max-width: 990px) {
|
||||
.services article{
|
||||
margin: 2em auto;
|
||||
width: 80%;
|
||||
}
|
||||
.services div{
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
196
home/static/home/css/index.css
Normal file
@@ -0,0 +1,196 @@
|
||||
:root{
|
||||
--c-background: #031D44; /*background*/
|
||||
--c-background-light: #04395E; /*background-highlight*/
|
||||
--c-boxes: #24719f;; /*boxes*/
|
||||
--c-lines: #87a9da; /*lines*/
|
||||
--c-text: #CAF0F8; /*text*/
|
||||
--c-other: #70A288; /*other*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
body{
|
||||
overflow-x: hidden;
|
||||
|
||||
background: rgb(0,0,0);
|
||||
background: -moz-linear-gradient(145deg, var(--c-background) 0%, var(--c-background-light) 100%);
|
||||
background: -webkit-linear-gradient(145deg, var(--c-background) 0%, var(--c-background-light) 100%);
|
||||
background: linear-gradient(145deg, var(--c-background) 0%, var(--c-background-light) 100%);
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
body .between h1{
|
||||
margin-top: 2em;
|
||||
text-align: center;
|
||||
color: var(--c-text);
|
||||
text-decoration: underline;
|
||||
font-size: 4em;
|
||||
}
|
||||
|
||||
.hidden{
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.apps-group{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.apps-group div{
|
||||
border-radius: 1em;
|
||||
}
|
||||
.apps-container{
|
||||
position: relative;
|
||||
display: flex;
|
||||
gap: 3em;
|
||||
width: 100%;
|
||||
margin: auto;
|
||||
justify-content: center;
|
||||
}
|
||||
.apps-container .chat,
|
||||
.apps-container .apps-group{
|
||||
|
||||
}
|
||||
|
||||
|
||||
.nav-drone{
|
||||
margin-top: 0em !important;
|
||||
margin-bottom: -9em;
|
||||
height: 20em;
|
||||
position: relative;
|
||||
}
|
||||
.nav-drone .video-background{
|
||||
height: 55vh;
|
||||
clip-path: polygon(0 0%, 15% 0, 30% 0%, 42% 0%, 61% 0%, 82% 0%, 100% 0%, 100% 94%, 82% 100%, 65% 96%, 47% 99%, 30% 90%, 14% 98%, 0 94%) !important;
|
||||
}
|
||||
#nav-drone-background-css:has(nav) nav{ /*TOHLE PATŘÍ NAVIGACI VYŘEŠIT*/
|
||||
margin-bottom: 8em;
|
||||
}
|
||||
|
||||
.spark-cursor{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
|
||||
position: absolute;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
|
||||
transform: translate(-20px, -20px);
|
||||
}
|
||||
.spark-cursor *{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.spark-cursor span{
|
||||
position:absolute;
|
||||
width: 2px;
|
||||
height: 20px;
|
||||
pointer-events: none;
|
||||
transform-origin: bottom;
|
||||
overflow: hidden;
|
||||
|
||||
filter: drop-shadow(0 0 0.5em #0f0) drop-shadow(0 0 1em #0f0);
|
||||
}
|
||||
.spark-cursor span.animate::before{
|
||||
display: block;
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #0f0;
|
||||
animation: animate-spark 1s ease-in-out forwards;
|
||||
}
|
||||
@keyframes animate-spark{
|
||||
0%{
|
||||
transform: translateY(100%);
|
||||
}
|
||||
100%{
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
}
|
||||
|
||||
.success-form-alert{
|
||||
display: none;
|
||||
background: #d4edda;
|
||||
color: #155724;
|
||||
padding: 10px;
|
||||
border: 1px solid #c3e6cb;
|
||||
border-radius: 5px;
|
||||
margin-top: 10px;
|
||||
position: relative;
|
||||
}
|
||||
.success-form-alert .close{
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 10px;
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 990px) {
|
||||
.apps-container{
|
||||
display: flex;
|
||||
margin: auto;
|
||||
flex-direction: column;
|
||||
width: 90%;
|
||||
gap: 1em;
|
||||
}
|
||||
.nav-drone{
|
||||
display: none;
|
||||
}
|
||||
.apps-container .apps-group {
|
||||
font-size: 0.9em;
|
||||
gap: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#reconnect{
|
||||
border-radius: 1em;
|
||||
color: white;
|
||||
padding: 4em;
|
||||
background-color: rgb(195 20 20);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
border: #7b0000 dashed 0.5em;
|
||||
}
|
||||
#reconnect img{
|
||||
width: 10em;
|
||||
}
|
||||
#reconnect button{
|
||||
position: relative;
|
||||
color: white;
|
||||
margin: auto 1em;
|
||||
padding: 1em;
|
||||
font: initial;
|
||||
font-size: 2em;
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
|
||||
|
||||
&:hover{
|
||||
animation: shake 0.4s ease-in-out infinite;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@keyframes shake {
|
||||
0% { transform: translateX(0); }
|
||||
25% { transform: translateX(-2px) rotate(-8deg); }
|
||||
50% { transform: translateX(2px) rotate(4deg); }
|
||||
75% { transform: translateX(-1px) rotate(-2deg); }
|
||||
100% { transform: translateX(0); }
|
||||
}
|
||||
BIN
home/static/home/img/carousel/content/camera.jpg
Normal file
|
After Width: | Height: | Size: 178 KiB |
BIN
home/static/home/img/carousel/content/italy.png
Normal file
|
After Width: | Height: | Size: 482 KiB |
BIN
home/static/home/img/carousel/content/programing.jpg
Normal file
|
After Width: | Height: | Size: 4.5 MiB |
1
home/static/home/img/carousel/next.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 18 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"><path d="M0.759,31.748l-0.507,-0.507c-0.336,-0.336 -0.336,-0.881 0,-1.218l14.023,-14.023l-14.023,-14.023c-0.336,-0.337 -0.336,-0.882 0,-1.218l0.507,-0.507c0.336,-0.336 0.881,-0.336 1.218,0l15.139,15.139c0.336,0.336 0.336,0.881 -0,1.218l-15.139,15.139c-0.337,0.336 -0.882,0.336 -1.218,-0Z" style="fill:#fff;fill-rule:nonzero;"/></svg>
|
||||
|
After Width: | Height: | Size: 773 B |
1
home/static/home/img/carousel/prev.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 18 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"><path d="M16.609,31.748l0.507,-0.507c0.336,-0.336 0.336,-0.881 -0,-1.218l-14.023,-14.023l14.023,-14.023c0.336,-0.337 0.336,-0.882 -0,-1.218l-0.507,-0.507c-0.336,-0.336 -0.881,-0.336 -1.218,0l-15.139,15.139c-0.336,0.336 -0.336,0.881 0,1.218l15.139,15.139c0.337,0.336 0.882,0.336 1.218,-0Z" style="fill:#fff;fill-rule:nonzero;"/></svg>
|
||||
|
After Width: | Height: | Size: 773 B |
BIN
home/static/home/img/portfolio/DAVO_logo_2024_bile.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
24
home/static/home/img/portfolio/logo_epinger.svg
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
home/static/home/img/portfolio/perlica-3.webp
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
129
home/static/home/js/anon-chat.js
Normal file
@@ -0,0 +1,129 @@
|
||||
$(document).ready(function () {
|
||||
console.log(Intl.DateTimeFormat().resolvedOptions().timeZone)
|
||||
|
||||
// Initialize WebSocket connection
|
||||
var ws_url = "";
|
||||
const ws_path = '/ws/anonChat/';
|
||||
|
||||
if(window.location.protocol === 'https:'){
|
||||
ws_url = 'wss://' + window.location.host + ws_path;
|
||||
}else{
|
||||
ws_url = 'ws://' + window.location.host + ws_path;
|
||||
}
|
||||
|
||||
console.log({'websocket_url': ws_url});
|
||||
|
||||
let socket = new WebSocket(ws_url);
|
||||
|
||||
// Select elements
|
||||
const $messageInput = $('#anon-message');
|
||||
const $sendButton = $('#send-anon-message');
|
||||
const $messagesContainer = $('.chat .messages');
|
||||
|
||||
const $reconnectButton = $('#reconnect button');
|
||||
|
||||
$('#reconnect').hide();
|
||||
|
||||
// Event: Connection opened
|
||||
socket.onopen = function () {
|
||||
console.log('WebSocket connection established.');
|
||||
};
|
||||
|
||||
// Event: Message received from the server
|
||||
socket.onmessage = function (event) {
|
||||
console.log('Message received:', event.data);
|
||||
|
||||
// Parse the JSON data
|
||||
const data = JSON.parse(event.data);
|
||||
|
||||
// Extract the message and display it
|
||||
if (data.message) {
|
||||
var time_formated = data.time;
|
||||
time_formated.replace(' pm', 'p.m.').replace(' am', 'a.m.');
|
||||
|
||||
/*
|
||||
<div>
|
||||
<sub>{{message.time}}</sub>
|
||||
<p>{{message.text}}</p>
|
||||
</div>
|
||||
*/
|
||||
|
||||
const $message = $('<div>').append($('<sub>').text(time_formated)).append($('<p>').text(data.message));
|
||||
|
||||
$messagesContainer.append($message);
|
||||
} else {
|
||||
console.warn('Invalid message format received:', data);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
// Event: Connection closed
|
||||
socket.onclose = function () {
|
||||
console.warn('WebSocket connection closed.');
|
||||
|
||||
$('#reconnect').show();
|
||||
};
|
||||
|
||||
// Event: Error occurred
|
||||
socket.onerror = function (error) {
|
||||
console.error('WebSocket error:', error);
|
||||
|
||||
$('#reconnect').show();
|
||||
};
|
||||
|
||||
$reconnectButton.on('click', function(){
|
||||
console.log("reconnecting!");
|
||||
|
||||
socket = new WebSocket(ws_url);
|
||||
});
|
||||
|
||||
// Send message to the server when the button is clicked
|
||||
$sendButton.on('click', function () {
|
||||
|
||||
const message = $messageInput.val().trim();
|
||||
|
||||
if (message) {
|
||||
socket.send(JSON.stringify({ message: message })); // Send the message to the server
|
||||
console.log('Message sent:', message);
|
||||
|
||||
var time = new Date();
|
||||
const monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
||||
const timeWithoutSeconds = time.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', hour12: false }); // `hour12: false` forces 24-hour format
|
||||
|
||||
// Format as "Nov. 25, 2024, 14:55"
|
||||
var time_output = `${monthNames[time.getMonth()]}. ${time.getDate()}, ${time.getFullYear()}, ${timeWithoutSeconds}`;
|
||||
|
||||
|
||||
const $sentMessage = $('<div>').append($('<sub>').text(time_output)).append($('<p>').text(message));
|
||||
|
||||
$messagesContainer.append($sentMessage);
|
||||
|
||||
// Clear the input field
|
||||
$messageInput.val('');
|
||||
|
||||
scroll_chat_to_bottom();
|
||||
|
||||
} else if((socket.readyState === WebSocket.OPEN) == false) {
|
||||
console.log("socket.readyState === WebSocket.OPEN: " + String(socket.readyState === WebSocket.OPEN));
|
||||
|
||||
$('#reconnect').show();
|
||||
} else {
|
||||
console.warn('Cannot send message. WebSocket is not open or message is empty.');
|
||||
|
||||
$('#reconnect').show();
|
||||
}
|
||||
});
|
||||
|
||||
// Allow pressing Enter to send the message
|
||||
$messageInput.on('keypress', function (event) {
|
||||
if (event.key === 'Enter') {
|
||||
$sendButton.click(); // Trigger the click event on the button
|
||||
}
|
||||
});
|
||||
|
||||
function scroll_chat_to_bottom(){
|
||||
// Animate scroll to bottom (500 miliseconds)
|
||||
$messagesContainer.animate({ scrollTop: $messagesContainer[0].scrollHeight }, 500);
|
||||
}
|
||||
});
|
||||
188
home/static/home/js/anon-direct-voice-chat.js
Normal file
@@ -0,0 +1,188 @@
|
||||
$(document).ready(function () {
|
||||
const localAudio = $('#direct-localAudio')[0];
|
||||
const remoteAudio = $('#direct-remoteAudio')[0];
|
||||
|
||||
const peerIdInput = $('#direct-peer-id-input');
|
||||
const connectBtn = $('#direct-connect-btn');
|
||||
const muteBtn = $('#direct-mute-btn');
|
||||
const disconnectBtn = $('#direct-disconnect-btn');
|
||||
|
||||
const acceptCallBtn = $('#direct-accept-call-btn');
|
||||
const denyCallBtn = $('#direct-deny-call-btn');
|
||||
|
||||
const copyIDButton = $(".direct-voice-chat .info");
|
||||
|
||||
let localStream = null;
|
||||
let currentCall = null;
|
||||
let incomingCall = null;
|
||||
let isMuted = false;
|
||||
|
||||
$('#incoming-call-container').hide();
|
||||
disconnectBtn.hide(); // Skryj disconnect tlačítko na začátku
|
||||
|
||||
const direct_peer = new Peer();
|
||||
|
||||
/*
|
||||
const direct_peer = new Peer(undefined, {
|
||||
host: 'peerjs.vontor.com',
|
||||
port: 443, // Use 443 for HTTPS
|
||||
path: '/app', // Ensure this matches the path configured on your server
|
||||
secure: true, // Enable TLS/SSL
|
||||
});
|
||||
*/
|
||||
|
||||
// Display your Peer ID
|
||||
direct_peer.on('open', (id) => {
|
||||
$('#direct-peer-id').text(id);
|
||||
});
|
||||
|
||||
// Get audio stream
|
||||
async function getAudioStream() {
|
||||
if (!localStream) {
|
||||
localStream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
||||
localAudio.srcObject = localStream;
|
||||
}
|
||||
return localStream;
|
||||
}
|
||||
|
||||
// Handle incoming call
|
||||
direct_peer.on('call', async (call) => {
|
||||
console.log("Incoming call...");
|
||||
incomingCall = call;
|
||||
connectBtn.prop('disabled', true);
|
||||
|
||||
$('#incoming-call-container').show(); // Zobraz příchozí hovor
|
||||
});
|
||||
|
||||
// Deny the incoming call
|
||||
denyCallBtn.on('click', async () => {
|
||||
if (incomingCall) {
|
||||
const conn = direct_peer.connect(incomingCall.peer);
|
||||
conn.on('open', () => {
|
||||
conn.send({ type: 'call-denied' });
|
||||
});
|
||||
incomingCall = null;
|
||||
}
|
||||
|
||||
$('#incoming-call-container').hide(); // Skryj kontejner
|
||||
connectBtn.prop('disabled', false); // Povolit connect tlačítko
|
||||
});
|
||||
|
||||
// Accept the incoming call
|
||||
acceptCallBtn.on('click', async () => {
|
||||
if (!incomingCall) {
|
||||
alert('No incoming call to accept.');
|
||||
return;
|
||||
}
|
||||
|
||||
const localStream = await getAudioStream();
|
||||
localAudio.srcObject = localStream;
|
||||
|
||||
incomingCall.answer(localStream);
|
||||
currentCall = incomingCall;
|
||||
incomingCall = null;
|
||||
|
||||
const conn = direct_peer.connect(currentCall.peer);
|
||||
conn.on('open', () => {
|
||||
conn.send({ type: 'call-accepted' });
|
||||
});
|
||||
|
||||
currentCall.on('stream', (remoteStream) => {
|
||||
remoteAudio.srcObject = remoteStream;
|
||||
});
|
||||
console.log("Incoming call accepted!");
|
||||
|
||||
$('#incoming-call-container').hide(); // Skryj kontejner
|
||||
peerIdInput.prop('disabled', true); // Disable input
|
||||
connectBtn.hide(); // Skryj connect tlačítko
|
||||
disconnectBtn.show(); // Zobraz disconnect tlačítko
|
||||
});
|
||||
|
||||
// Connect and make a call
|
||||
connectBtn.on('click', async () => {
|
||||
const peerId = peerIdInput.val();
|
||||
|
||||
if (!peerId) {
|
||||
alert('Please enter an ID to connect to.');
|
||||
return;
|
||||
} else if (peerId === $('#direct-peer-id').text()) {
|
||||
alert('Dont use own ID to connect!');
|
||||
return;
|
||||
}
|
||||
|
||||
const localStream = await getAudioStream();
|
||||
localAudio.srcObject = localStream;
|
||||
|
||||
const conn = direct_peer.connect(peerId);
|
||||
conn.on('data', (data) => {
|
||||
if (data.type === 'call-accepted') {
|
||||
console.log('The other user has accepted the call!');
|
||||
} else if (data.type === 'call-denied') {
|
||||
console.log('The other user has denied the call!');
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
const call = direct_peer.call(peerId, localStream);
|
||||
currentCall = call;
|
||||
|
||||
call.on('stream', (remoteStream) => {
|
||||
remoteAudio.srcObject = remoteStream;
|
||||
});
|
||||
|
||||
peerIdInput.prop('disabled', true); // Disable input
|
||||
connectBtn.hide(); // Skryj connect tlačítko
|
||||
disconnectBtn.show(); // Zobraz disconnect tlačítko
|
||||
console.log("Call started!");
|
||||
});
|
||||
|
||||
// Disconnect functionality
|
||||
disconnectBtn.on('click', () => {
|
||||
handleDisconnect();
|
||||
});
|
||||
|
||||
function handleDisconnect() {
|
||||
if (currentCall) {
|
||||
currentCall.close();
|
||||
currentCall = null;
|
||||
}
|
||||
|
||||
if (localStream) {
|
||||
localStream.getTracks().forEach(track => track.stop());
|
||||
localStream = null;
|
||||
}
|
||||
remoteAudio.srcObject = null;
|
||||
localAudio.srcObject = null;
|
||||
|
||||
disconnectBtn.hide(); // Skryj disconnect tlačítko
|
||||
connectBtn.show(); // Zobraz connect tlačítko
|
||||
peerIdInput.prop('disabled', false); // Enable input
|
||||
|
||||
console.log('Disconnected.');
|
||||
}
|
||||
|
||||
// Mute/Unmute functionality
|
||||
muteBtn.on('click', () => {
|
||||
if (!localStream) {
|
||||
alert('No audio stream available.');
|
||||
return;
|
||||
}
|
||||
|
||||
isMuted = !isMuted;
|
||||
|
||||
localStream.getAudioTracks().forEach(track => {
|
||||
track.enabled = !isMuted;
|
||||
});
|
||||
|
||||
muteBtn.text(isMuted ? 'Unmute' : 'Mute');
|
||||
});
|
||||
|
||||
copyIDButton.on('click', () => {
|
||||
console.log("copied!");
|
||||
// Get the text field
|
||||
var copyText = $('#direct-peer-id').text();
|
||||
|
||||
// Copy the text inside the text field
|
||||
navigator.clipboard.writeText(copyText);
|
||||
});
|
||||
});
|
||||
160
home/static/home/js/anon-voice-chat.js
Normal file
@@ -0,0 +1,160 @@
|
||||
$(document).ready(function () {
|
||||
let peer;
|
||||
let socket;
|
||||
let currentCall;
|
||||
|
||||
var state;
|
||||
|
||||
// Setup WebSocket
|
||||
const ws_path = "/ws/AnonVoice/";
|
||||
var ws_url = "";
|
||||
|
||||
if (window.location.protocol === 'https:') {
|
||||
ws_url = 'wss://' + window.location.host + ws_path;
|
||||
} else {
|
||||
ws_url = 'ws://' + window.location.host + ws_path;
|
||||
}
|
||||
|
||||
// Initialize PeerJS
|
||||
/*peer = new Peer({
|
||||
host: 'peerjs.vontor.cz',
|
||||
port: 443,
|
||||
secure: true,
|
||||
key: 'publicAllowed'
|
||||
});*/
|
||||
|
||||
socket = new WebSocket(ws_url);
|
||||
|
||||
socket.onopen = function (event) {
|
||||
console.log("Connected to: Global voice room.");
|
||||
|
||||
socket.send(JSON.stringify({ type: "request_user_count" }));
|
||||
};
|
||||
|
||||
socket.onmessage = function (event) {
|
||||
const data = JSON.parse(event.data);
|
||||
|
||||
if (data.type === "user_count_message") {
|
||||
$('#connected-people').text(data.users_count);
|
||||
} else if (data.type === "peer_id_message") {
|
||||
// Start call with received peer ID
|
||||
startCall(data.peer_id);
|
||||
}
|
||||
};
|
||||
|
||||
socket.onclose = function (event) {
|
||||
$("#my-status").removeClass('online');
|
||||
|
||||
if (state !== false) {
|
||||
socket.send(JSON.stringify({ type: "disconnecting_user" }));
|
||||
}
|
||||
console.log("Disconnected from the voice room.");
|
||||
$("#global-connect-btn").removeClass('hidden');
|
||||
$("#global-disconnect-btn").addClass('hidden');
|
||||
};
|
||||
|
||||
socket.onerror = function (error) {
|
||||
$("#my-status").removeClass('online');
|
||||
console.log("WebSocket Error: ", error);
|
||||
};
|
||||
|
||||
//button connect
|
||||
function connect() {
|
||||
$("#my-status").addClass('online');
|
||||
state = true;
|
||||
|
||||
peer = new Peer();
|
||||
|
||||
/*
|
||||
peer = new Peer(undefined, {
|
||||
host: 'peerjs.vontor.com',
|
||||
port: 443, // Use 443 for HTTPS
|
||||
path: '/app', // Ensure this matches the path configured on your server
|
||||
secure: true, // Enable TLS/SSL
|
||||
});
|
||||
*/
|
||||
|
||||
peer.on('open', function (id) {
|
||||
console.log('My peer ID is: ' + id);
|
||||
|
||||
socket.send(JSON.stringify({ type: "connected_user", peer_id: id }));
|
||||
});
|
||||
|
||||
peer.on('call', function (call) {
|
||||
navigator.mediaDevices.getUserMedia({ audio: true }).then(stream => {
|
||||
call.answer(stream);
|
||||
currentCall = call;
|
||||
|
||||
call.on('stream', function (remoteStream) {
|
||||
playAudio(remoteStream);
|
||||
});
|
||||
}).catch(function (err) {
|
||||
console.error('Failed to get local stream', err);
|
||||
});
|
||||
});
|
||||
|
||||
$("#global-connect-btn").addClass('hidden');
|
||||
$("#global-disconnect-btn").removeClass('hidden');
|
||||
|
||||
$(".global-voice-chat").removeClass('active-call');
|
||||
}
|
||||
|
||||
//connecting to peer
|
||||
function startCall(remotePeerId) {
|
||||
//getting mic
|
||||
navigator.mediaDevices.getUserMedia({ audio: true }).then(stream => {
|
||||
const call = peer.call(remotePeerId, stream);
|
||||
currentCall = call;
|
||||
|
||||
call.on('stream', function (remoteStream) {
|
||||
playAudio(remoteStream);
|
||||
});
|
||||
|
||||
call.on('error', function (err) {
|
||||
console.error('Call failed:', err);
|
||||
});
|
||||
|
||||
}).catch(function (err) {
|
||||
console.error('Failed to get local stream', err);
|
||||
});
|
||||
}
|
||||
|
||||
//button disconnect
|
||||
function disconnect() {
|
||||
state = false;
|
||||
|
||||
if (currentCall) {
|
||||
currentCall.close();
|
||||
console.log("Call closed.");
|
||||
}
|
||||
if (peer) {
|
||||
peer.disconnect();
|
||||
console.log("Peer disconnected.");
|
||||
}
|
||||
if (socket) {
|
||||
socket.send(JSON.stringify({ type: "disconnecting_user" }));
|
||||
}
|
||||
|
||||
$("#global-connect-btn").removeClass('hidden');
|
||||
$("#global-disconnect-btn").addClass('hidden');
|
||||
|
||||
$("#my-status").removeClass('online');
|
||||
|
||||
}
|
||||
|
||||
function playAudio(stream) {
|
||||
const audio = $('#global-remoteAudio')[0];
|
||||
audio.srcObject = stream;
|
||||
audio.play();
|
||||
}
|
||||
|
||||
window.onbeforeunload = function () {
|
||||
if (socket && state !== false) {
|
||||
socket.send(JSON.stringify({ type: "disconnecting_user" }));
|
||||
}
|
||||
};
|
||||
|
||||
// Example usage
|
||||
$('#global-connect-btn').click(connect);
|
||||
$('#global-disconnect-btn').click(disconnect);
|
||||
});
|
||||
149
home/static/home/js/carousel.js
Normal file
@@ -0,0 +1,149 @@
|
||||
$(document).ready(function() {
|
||||
let carousel = $('.carousel');
|
||||
let carouselInner = $('.carousel-inner');
|
||||
let prev = $('.carousel-controls .prev');
|
||||
let next = $('.carousel-controls .next');
|
||||
let totalSlides = $('.carousel-inner .carousel-item').length;
|
||||
let step = 100 / totalSlides;
|
||||
let activeSlide = 0;
|
||||
let activeIndicator = 0;
|
||||
let direction = -1;
|
||||
let jump = 1;
|
||||
let interval = 3000;
|
||||
let time;
|
||||
|
||||
// Init carousel
|
||||
carouselInner.css('minWidth', totalSlides * 100 + '%');
|
||||
loadIndicators();
|
||||
loop(true);
|
||||
|
||||
// Carousel events
|
||||
next.on('click', function() {
|
||||
console.log("next");
|
||||
slideToNext();
|
||||
});
|
||||
|
||||
prev.on('click', function() {
|
||||
console.log("prev");
|
||||
slideToPrev();
|
||||
});
|
||||
|
||||
carouselInner.on('transitionend', function() {
|
||||
if (direction === -1) {
|
||||
if (jump > 1) {
|
||||
for (let i = 0; i < jump; i++) {
|
||||
activeSlide++;
|
||||
carouselInner.append(carouselInner.children().first());
|
||||
}
|
||||
} else {
|
||||
activeSlide++;
|
||||
carouselInner.append(carouselInner.children().first());
|
||||
}
|
||||
} else if (direction === 1) {
|
||||
if (jump > 1) {
|
||||
for (let i = 0; i < jump; i++) {
|
||||
activeSlide--;
|
||||
carouselInner.prepend(carouselInner.children().last());
|
||||
}
|
||||
} else {
|
||||
activeSlide--;
|
||||
carouselInner.prepend(carouselInner.children().last());
|
||||
}
|
||||
}
|
||||
|
||||
carouselInner.css({
|
||||
transition: 'none',
|
||||
transform: 'translateX(0%)'
|
||||
});
|
||||
|
||||
setTimeout(function() {
|
||||
jump = 1;
|
||||
carouselInner.css('transition', 'all ease 1.5s');
|
||||
});
|
||||
updateIndicators();
|
||||
});
|
||||
|
||||
$(document).on('click', '.carousel-indicators span', function() {
|
||||
let slideTo = parseInt($(this).data('slide-to'));
|
||||
let indicators = $('.carousel-indicators span');
|
||||
indicators.each(function(index) {
|
||||
if ($(this).hasClass('active')) {
|
||||
activeIndicator = index;
|
||||
}
|
||||
});
|
||||
|
||||
if (slideTo - activeIndicator > 1) {
|
||||
jump = slideTo - activeIndicator;
|
||||
step = jump * step;
|
||||
slideToNext();
|
||||
} else if (slideTo - activeIndicator === 1) {
|
||||
slideToNext();
|
||||
} else if (slideTo - activeIndicator < 0) {
|
||||
if (Math.abs(slideTo - activeIndicator) > 1) {
|
||||
jump = Math.abs(slideTo - activeIndicator);
|
||||
step = jump * step;
|
||||
slideToPrev();
|
||||
}
|
||||
slideToPrev();
|
||||
}
|
||||
step = 100 / totalSlides;
|
||||
});
|
||||
|
||||
carousel.on('mouseover', function() {
|
||||
loop(false);
|
||||
});
|
||||
|
||||
carousel.on('mouseout', function() {
|
||||
loop(true);
|
||||
});
|
||||
|
||||
// Carousel functions
|
||||
function loadIndicators() {
|
||||
for (let index = 0; index < totalSlides; index++) {
|
||||
if (index === 0) {
|
||||
$('.carousel-indicators').append('<span data-slide-to="' + index + '" class="active"></span>');
|
||||
} else {
|
||||
$('.carousel-indicators').append('<span data-slide-to="' + index + '"></span>');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateIndicators() {
|
||||
if (activeSlide > (totalSlides - 1)) {
|
||||
activeSlide = 0;
|
||||
} else if (activeSlide < 0) {
|
||||
activeSlide = totalSlides - 1;
|
||||
}
|
||||
$('.carousel-indicators span.active').removeClass('active');
|
||||
$('.carousel-indicators span').eq(activeSlide).addClass('active');
|
||||
}
|
||||
|
||||
function slideToNext() {
|
||||
if (direction === 1) {
|
||||
direction = -1;
|
||||
carouselInner.prepend(carouselInner.children().last());
|
||||
}
|
||||
|
||||
carousel.css('justifyContent', 'flex-start');
|
||||
carouselInner.css('transform', 'translateX(-' + step + '%)');
|
||||
}
|
||||
|
||||
function slideToPrev() {
|
||||
if (direction === -1) {
|
||||
direction = 1;
|
||||
carouselInner.append(carouselInner.children().first());
|
||||
}
|
||||
carousel.css('justifyContent', 'flex-end');
|
||||
carouselInner.css('transform', 'translateX(' + step + '%)');
|
||||
}
|
||||
|
||||
function loop(status) {
|
||||
if (status === true) {
|
||||
time = setInterval(function() {
|
||||
slideToNext();
|
||||
}, interval);
|
||||
} else {
|
||||
clearInterval(time);
|
||||
}
|
||||
}
|
||||
});
|
||||
33
home/static/home/js/drone.js
Normal file
@@ -0,0 +1,33 @@
|
||||
$(document).ready(function () {
|
||||
function setVideoDroneQuality() {
|
||||
$sourceElement = $("#video-source");
|
||||
|
||||
const videoSources = {
|
||||
fullHD: 'static/home/video/drone-background-video-1080p.mp4', // For desktops (1920x1080)
|
||||
hd: 'static/home/video/drone-background-video-720p.mp4', // For tablets/smaller screens (1280x720)
|
||||
lowRes: 'static/home/video/drone-background-video-480p.mp4' // For mobile devices or low performance (854x480)
|
||||
};
|
||||
|
||||
const screenWidth = $(window).width(); // Get screen width
|
||||
|
||||
// Determine the appropriate video source
|
||||
if (screenWidth >= 1920) {
|
||||
$sourceElement.attr('src', "https://vontor-cz.s3.eu-central-1.amazonaws.com/" + videoSources.fullHD);
|
||||
} else if (screenWidth >= 1280) {
|
||||
$sourceElement.attr('src', "https://vontor-cz.s3.eu-central-1.amazonaws.com/" + videoSources.hd);
|
||||
} else {
|
||||
$sourceElement.attr('src', "https://vontor-cz.s3.eu-central-1.amazonaws.com/" + videoSources.lowRes);
|
||||
}
|
||||
|
||||
// Reload the video
|
||||
$('#drone-video')[0].load();
|
||||
|
||||
console.log("video set!");
|
||||
|
||||
}
|
||||
|
||||
setTimeout(1000);
|
||||
|
||||
setVideoDroneQuality();
|
||||
//$("#debug-drone").click(setVideoDroneQuality);
|
||||
});
|
||||
72
home/static/home/js/global/contact-me.js
Normal file
@@ -0,0 +1,72 @@
|
||||
$(document).ready(function () {
|
||||
$("#contactme-form").submit(function (event) {
|
||||
event.preventDefault(); // Prevent normal form submission
|
||||
|
||||
$.ajax({
|
||||
url: "/submit-contactme/", // URL of the Django view
|
||||
type: "POST",
|
||||
data: $(this).serialize(), // Serialize form data
|
||||
success: function (response) {
|
||||
if (response.success) {
|
||||
close_contact();
|
||||
|
||||
$("#contactme-form .success-form-alert").fadeIn();
|
||||
$("#contactme-form")[0].reset(); // Clear the form
|
||||
|
||||
alert("Zpráva odeslaná!")
|
||||
}
|
||||
},
|
||||
error: function (response) {
|
||||
alert("Zpráva nebyla odeslaná, zkontrolujte si připojení k internetu nebo naskytl u nás problém :(")
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
$("#contactme-form .success-form .close").click(function () {
|
||||
$("#contactme-form .success-form-alert").fadeOut();
|
||||
});
|
||||
|
||||
var opened_contact = false;
|
||||
|
||||
$(document).on("click", ".contact-me .opening", function () {
|
||||
console.log("toggle mail");
|
||||
|
||||
const opening = $(".contact-me .opening");
|
||||
|
||||
|
||||
|
||||
|
||||
// Check if we're opening or closing
|
||||
if (opened_contact === false) {
|
||||
// Toggle rotation
|
||||
opening.toggleClass('rotate-opening');
|
||||
|
||||
// Wait for the rotation to finish
|
||||
setTimeout(function() {
|
||||
$(".contact-me .content").addClass('content-moveup-index');
|
||||
}, 500);
|
||||
|
||||
setTimeout(function() {
|
||||
$(".contact-me .content")[0].offsetHeight;
|
||||
|
||||
$(".contact-me .content").addClass('content-moveup');
|
||||
}, 1000); // Small delay to trigger transition
|
||||
|
||||
opened_contact = true;
|
||||
} else {
|
||||
close_contact();
|
||||
}
|
||||
});
|
||||
|
||||
function close_contact(){
|
||||
$(".contact-me .content").removeClass('content-moveup');
|
||||
|
||||
setTimeout(function() {
|
||||
$(".contact-me .content").toggleClass('content-moveup-index');
|
||||
$(".contact-me .opening").toggleClass('rotate-opening');
|
||||
}, 700);
|
||||
|
||||
opened_contact = false;
|
||||
}
|
||||
});
|
||||
29
home/static/home/js/index.js
Normal file
@@ -0,0 +1,29 @@
|
||||
$(document).ready(function () {
|
||||
|
||||
$("body").click(function(event){
|
||||
var randomId = "spark-" + Math.floor(Math.random() * 100000);
|
||||
var $spark = $("<div>").addClass("spark-cursor").attr("id", randomId);
|
||||
$("body").append($spark);
|
||||
|
||||
// Nastavení pozice
|
||||
$spark.css({
|
||||
"top": event.pageY + "px",
|
||||
"left": event.pageX + "px",
|
||||
"filter": "hue-rotate(" + Math.random() * 360 + "deg)"
|
||||
});
|
||||
|
||||
for (let index = 0; index < 8; index++) {
|
||||
let $span = $("<span>");
|
||||
$span.css("transform", 'rotate(' + (index * 45) +"deg)" );
|
||||
$spark.append($span);
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
$spark.find("span").addClass("animate");
|
||||
}, 10);
|
||||
|
||||
setTimeout(function(){
|
||||
$("#" + randomId).remove();
|
||||
}, 1000);
|
||||
});
|
||||
});
|
||||
13
home/static/home/js/portfolio.js
Normal file
@@ -0,0 +1,13 @@
|
||||
$(document).ready(function () {
|
||||
var doorOpen= false;
|
||||
|
||||
$(".door").click(function(){
|
||||
doorOpen = !doorOpen;//převrátí hodnotu
|
||||
|
||||
if ($(".door").hasClass('door-open')){
|
||||
$(".door").removeClass('door-open');
|
||||
}else{
|
||||
$(".door").addClass('door-open');
|
||||
}
|
||||
});
|
||||
});
|
||||
18
home/templates/home/components/carousel.html
Normal file
@@ -0,0 +1,18 @@
|
||||
{% load static %}
|
||||
<!--<div class="carousel">
|
||||
<div class="carousel-inner">
|
||||
<div style="background-image: url('{% static "home/img/carousel/content/italy.png" %}');" class="carousel-item carousel-item-first"><h1></h1></div>
|
||||
<div style="background-image: url('{% static "home/img/carousel/content/camera.jpg" %}');" class="carousel-item carousel-item-second"><h1></h1></div>
|
||||
<div style="background-image: url('{% static "home/img/carousel/content/programing.jpg" %}');" class="carousel-item carousel-item-third"><h1></h1></div>
|
||||
<div class="carousel-item carousel-item-fourth"><h1></h1></div>
|
||||
<div class="carousel-item carousel-item-fifth"><h1></h1></div>
|
||||
<div class="carousel-item carousel-item-sixth"><h1></h1></div>
|
||||
</div>
|
||||
<div class="carousel-controls">
|
||||
<span class="prev"></span>
|
||||
<span class="next"></span>
|
||||
</div>
|
||||
<div class="carousel-indicators"></div>
|
||||
</div>
|
||||
|
||||
<script src="{% static "home/js/carousel.js" %}"></script>-->
|
||||
22
home/templates/home/components/demo/chat.html
Normal file
@@ -0,0 +1,22 @@
|
||||
{% load static %}
|
||||
<div class="chat">
|
||||
<div class="title-bar">
|
||||
Chat
|
||||
</div>
|
||||
<div class="messages">
|
||||
{% for message in last_messages %}
|
||||
<div>
|
||||
<sub>{{message.time}}</sub>
|
||||
<p>{{message.text}}</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="send-box">
|
||||
<input placeholder="what's on your mind now?..." type="text" name="anon-message" id="anon-message">
|
||||
<button id="send-anon-message" type="submit">
|
||||
<i class="fa-solid fa-paper-plane"></i><!--send button-->
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<script src="{% static '/home/js/anon-chat.js' %}"></script>
|
||||
30
home/templates/home/components/demo/direct-voice-chat.html
Normal file
@@ -0,0 +1,30 @@
|
||||
{% load static %}
|
||||
<div class="direct-voice-chat">
|
||||
<div class="title-bar">
|
||||
Direct Voice Call
|
||||
</div>
|
||||
<div class="info">
|
||||
<p>ID: <span id="direct-peer-id"></span></p>
|
||||
<sub><i class="fa-solid fa-clone"></i></sub>
|
||||
</div>
|
||||
<div class="connection">
|
||||
<input id="direct-peer-id-input" type="text" placeholder="Inser ID what you want to call...">
|
||||
|
||||
<button id="direct-connect-btn"><i class="fa-solid fa-phone"></i></button> <!--connect button-->
|
||||
<!--this will replace connect button and then otherwise-->
|
||||
<button id="direct-disconnect-btn">Disconnect</button><!--disconnect button-->
|
||||
</div>
|
||||
|
||||
<div id="incoming-call-container">
|
||||
<p>Incoming call!</p>
|
||||
|
||||
<button id="direct-accept-call-btn"><i class="fa-solid fa-phone"></i></button><!--decline button-->
|
||||
<button id="direct-deny-call-btn"><i class="fa-solid fa-phone-slash"></i></button><!--accept button-->
|
||||
</div>
|
||||
</div>
|
||||
<audio id="direct-localAudio" autoplay muted></audio>
|
||||
<audio id="direct-remoteAudio" autoplay></audio>
|
||||
|
||||
<script src="https://unpkg.com/peerjs@1.5.4/dist/peerjs.min.js"></script> <!---->
|
||||
|
||||
<script src="{% static 'home/js/anon-direct-voice-chat.js' %}"></script>
|
||||
27
home/templates/home/components/demo/global-voice-chat.html
Normal file
@@ -0,0 +1,27 @@
|
||||
{% load static %}
|
||||
<div class="global-voice-chat">
|
||||
<div class="title-bar">
|
||||
Global Voice Room
|
||||
</div>
|
||||
<div class="info">
|
||||
<div>
|
||||
<i class="fa-solid fa-user-group"></i><span id="connected-people"></span>
|
||||
</div>
|
||||
<div>
|
||||
Status: <i id="my-status" class="fa-solid fa-circle"></i>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="controls">
|
||||
<button id="global-connect-btn"><i class="fa-solid fa-phone"></i></button>
|
||||
<!--the buttons will replace eatchother-->
|
||||
<button id="global-disconnect-btn" class="hidden"><i class="fa-solid fa-phone-slash"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
<audio id="global-remoteAudio" autoplay></audio>
|
||||
|
||||
<script src="https://unpkg.com/peerjs@1.5.4/dist/peerjs.min.js"></script> <!---->
|
||||
|
||||
<script src="{% static 'home/js/anon-voice-chat.js' %}"></script>
|
||||
46
home/templates/home/components/drony.html
Normal file
@@ -0,0 +1,46 @@
|
||||
{% load static %}
|
||||
<div class="drone only-desktop">
|
||||
|
||||
<video id="drone-video" class="video-background" autoplay muted loop playsinline>
|
||||
<source id="video-source" type="video/mp4">
|
||||
Your browser does not support video.
|
||||
</video>
|
||||
|
||||
<article>
|
||||
<header>
|
||||
<h1>Letecké snímky dronem</h1>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<section>
|
||||
<h2>Opravnění</h2>
|
||||
|
||||
|
||||
A1, A2, A3 a průkaz na vysílačku!
|
||||
|
||||
Mohu garantovat bezpečný provoz dronu i ve složitějších podmínkách. Mám také možnost žádat o povolení k letu v blízkosti letišť!
|
||||
|
||||
</section>
|
||||
<section>
|
||||
<h2>Cena</h2>
|
||||
|
||||
Nabízím letecké záběry dronem <br>za cenu <u>3 000 Kč</u>.
|
||||
|
||||
Pokud se nacházíte v Ostravě, doprava je zdarma. Pro oblasti mimo Ostravu účtuji 10 Kč/km.
|
||||
|
||||
Cena se může odvíjet ještě podle složitosti získaní povolení.*
|
||||
</section>
|
||||
<section>
|
||||
<h2>Výstup</h2>
|
||||
|
||||
Rád Vám připravím jednoduchý sestřih videa, který můžete rychle použít, nebo Vám mohu poskytnout samotné záběry k vlastní editaci. <br>
|
||||
|
||||
</section>
|
||||
</main>
|
||||
<div>
|
||||
V případě zájmu mě neváhejte<br><a href="#contacts">kontaktovat!</a>
|
||||
</div>
|
||||
</article>
|
||||
<script src="{% static 'home/js/drone.js' %}"></script>
|
||||
</div>
|
||||
<!--<button id="debug-drone">force reload</button>-->
|
||||
21
home/templates/home/components/global/contact-me.html
Normal file
@@ -0,0 +1,21 @@
|
||||
{% load static %}
|
||||
|
||||
|
||||
|
||||
<div class="contact-me">
|
||||
<div class="opening">
|
||||
<i class="fa-solid fa-arrow-pointer" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="content">
|
||||
<form method="post" id="contactme-form">
|
||||
{% csrf_token %}
|
||||
{{ contactme_form }}
|
||||
<input type="submit" value="Submit">
|
||||
|
||||
</form>
|
||||
</div>
|
||||
<div class="cover"></div>
|
||||
<div class="triangle"></div>
|
||||
|
||||
</div>
|
||||
<script src="{% static 'home/js/global/contact-me.js' %}"></script>
|
||||
28
home/templates/home/components/global/footer.html
Normal file
@@ -0,0 +1,28 @@
|
||||
<footer id="contacts">
|
||||
<div class="logo">
|
||||
<h1>vontor.cz</h1>
|
||||
</div>
|
||||
<address>
|
||||
Written by <b>David Bruno Vontor</b><br>
|
||||
<p>Tel.: <a href="tel:+420 605 512 624"><u>+420 605 512 624</u></a></p>
|
||||
<p>E-mail: <a href="mailto:brunovontor@gmail.com"><u>brunovontor@gmail.com</u></a></p>
|
||||
<p>IČO: <a href="https://www.rzp.cz/verejne-udaje/cs/udaje/vyber-subjektu;ico=21613109;"><u>21613109</u></a></p>
|
||||
</address>
|
||||
<div class="contacts">
|
||||
<a href="https://github.com/Brunobrno">
|
||||
<i class="fa fa-github"></i>
|
||||
</a>
|
||||
<a href="https://www.instagram.com/brunovontor/">
|
||||
<i class="fa fa-instagram"></i>
|
||||
</a>
|
||||
<a href="https://twitter.com/BVontor">
|
||||
<i class="fa-brands fa-x-twitter"></i>
|
||||
</a>
|
||||
<a href="https://steamcommunity.com/id/Brunobrno/">
|
||||
<i class="fa-brands fa-steam"></i>
|
||||
</a>
|
||||
<a href="www.youtube.com/@brunovontor">
|
||||
<i class="fa-brands fa-youtube"></i>
|
||||
</a>
|
||||
</div>
|
||||
</footer>
|
||||
28
home/templates/home/components/introduction.html
Normal file
@@ -0,0 +1,28 @@
|
||||
<div class="wrapper">
|
||||
<div class="introduction">
|
||||
<article>
|
||||
<header>
|
||||
<h1>Úvod</h1>
|
||||
</header>
|
||||
<main>
|
||||
Tato stránka prezentuje mé projekty, služby a portfolio. Neustále se zdokonaluji a rozšiřuji své schopnosti v oblasti webového vývoje, správy serverů a nových technologií.
|
||||
</main>
|
||||
</article>
|
||||
|
||||
</div>
|
||||
<div class="animation-introduction">
|
||||
<ul class="circles">
|
||||
<li></li>
|
||||
<li></li>
|
||||
<li></li>
|
||||
<li></li>
|
||||
<li></li>
|
||||
<li></li>
|
||||
<li></li>
|
||||
<li></li>
|
||||
<li></li>
|
||||
<li></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
33
home/templates/home/components/portfolio.html
Normal file
@@ -0,0 +1,33 @@
|
||||
{% load static %}
|
||||
<div class="portfolio" id="portfolio">
|
||||
<header>
|
||||
<h1>Portfolio</h1>
|
||||
</header>
|
||||
|
||||
<div>
|
||||
<span class="door"><i class="fa-solid fa-arrow-pointer"></i></span>
|
||||
<article>
|
||||
<header>
|
||||
<a href="https://davo1.cz"><img src="{% static 'home\img\portfolio\DAVO_logo_2024_bile.png' %}" alt="davo1.cz logo"></a>
|
||||
</header>
|
||||
<main>
|
||||
</main>
|
||||
</article>
|
||||
<article>
|
||||
<header>
|
||||
<a href="https://perlica.cz"><img src="{% static 'home\img\portfolio\perlica-3.webp' %}" alt="Perlica logo"></a>
|
||||
</header>
|
||||
<main>
|
||||
</main>
|
||||
</article>
|
||||
<article>
|
||||
<header>
|
||||
<a href="http://epinger2.cz"><img src="{% static 'home\img\portfolio\logo_epinger.svg' %}" alt="Epinger2 logo"></a>
|
||||
</header>
|
||||
<main>
|
||||
</main>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<script src="{% static 'home/js/portfolio.js' %}"></script>
|
||||
46
home/templates/home/components/services.html
Normal file
@@ -0,0 +1,46 @@
|
||||
<div class="services" id="services">
|
||||
<header>
|
||||
<i class="fa-solid fa-briefcase"></i>
|
||||
<h1>Services</h1>
|
||||
</header>
|
||||
|
||||
<div>
|
||||
<article>
|
||||
<header>
|
||||
<i class="fa-solid fa-pen-ruler"></i>
|
||||
<h1>Úprava webu</h1>
|
||||
</header>
|
||||
<main>
|
||||
Oprava a modernizace starších webových stránek.<br>
|
||||
Opravy designu, vylepšení uživatelského rozhraní.<br>
|
||||
Řešení chyb v JavaScriptu a optimalizace kódu.
|
||||
</main>
|
||||
</article>
|
||||
<article>
|
||||
<header>
|
||||
<i class="fa-solid fa-globe"></i>
|
||||
<h1>Webové stránky</h1>
|
||||
</header>
|
||||
<main>
|
||||
Tvorba webových aplikací pomocí frameworku Django.<br>
|
||||
Optimalizace pro vyhledávače (SEO), správné užití HTML a meta tagů.<br>
|
||||
Integrace Google Search Console pro rychlejší indexaci a Google Analytics pro analýzu návštěvnosti.<br>
|
||||
Řešení databáze s využitím Docker compose.<br>
|
||||
Hosting složitých aplikací, jednoduché prezentační weby s PHP.<br>
|
||||
Správa domén, DNS záznamů a ochrana přes Cloudflare.<br>
|
||||
Možnost návrhu aplikace prostřednictvím UML diagramů.
|
||||
</main>
|
||||
</article>
|
||||
<article>
|
||||
<header>
|
||||
<i class="fa-solid fa-code"></i>
|
||||
<h1>Webová aplikace</h1>
|
||||
</header>
|
||||
<main>
|
||||
Vývoj plně dynamických webových aplikací na míru.<br>
|
||||
Real-time aktualizace, REST API, uživatelské účty.<br>
|
||||
Integrace platební brány Stripe a dalších funkcí.
|
||||
</main>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
69
home/templates/home/index.html
Normal file
@@ -0,0 +1,69 @@
|
||||
{% load static %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
{% include "utilities/head.html" %}
|
||||
|
||||
<title>Home - vontor.cz</title>
|
||||
|
||||
|
||||
<link rel="stylesheet" href="{% static "home/css/components/carousel.css" %}">
|
||||
|
||||
<link rel="stylesheet" href="{% static 'home/css/components/introduction.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'home/css/components/portfolio.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'home/css/components/services.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'home/css/components/demo/chat.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'home/css/components/drone.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'home/css/components/demo/direct-voice-chat.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'home/css/components/demo/global-voice-chat.css' %}">
|
||||
|
||||
{% include "home/utilities/head.html" %}
|
||||
</head>
|
||||
<body tabindex="0">
|
||||
|
||||
{% include "home/components/carousel.html" %}
|
||||
<div class="drone nav-drone">
|
||||
<!--<video src="https://vontor-cz.s3.eu-central-1.amazonaws.com/home/video/drone-background-video-720p.mp4" class="video-background" autoplay muted loop playsinline>
|
||||
<source id="video-source" type="video/mp4">
|
||||
Your browser does not support video.
|
||||
</video>
|
||||
<span id="nav-drone-background-css"></span>-->
|
||||
</div>
|
||||
|
||||
|
||||
{% include "utilities/nav.html" %}
|
||||
|
||||
{% include 'home/components/introduction.html' %}
|
||||
{% include "home/components/drony.html" %}
|
||||
|
||||
{% include 'home/components/services.html' %}
|
||||
{% include 'home/components/portfolio.html' %}
|
||||
|
||||
|
||||
<div class="between">
|
||||
<h1>Demo</h1>
|
||||
</div>
|
||||
<div class="apps-container">
|
||||
{% include "home/components/demo/chat.html" %}
|
||||
<div class="apps-group">
|
||||
{% include 'home/components/demo/direct-voice-chat.html' %}
|
||||
{% include 'home/components/demo/global-voice-chat.html' %}
|
||||
</div>
|
||||
|
||||
<div id="reconnect" class="hidden">
|
||||
<h1>You lost connection!</h1>
|
||||
|
||||
<img src="{% static 'img/errors/error_icon.png' %}" alt="error icon">
|
||||
<button><i class="fa-solid fa-rotate-right"></i></button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="between">
|
||||
<h1>Contact me!</h1>
|
||||
</div>
|
||||
{% include 'home/components/global/contact-me.html' %}
|
||||
|
||||
{% include 'home/components/global/footer.html' %}
|
||||
<script src="{% static 'home/js/index.js' %}"></script>
|
||||
</body>
|
||||
</html>
|
||||
15
home/templates/home/mail/contact-me.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
</head>
|
||||
<body style="font-family: Arial, sans-serif; background-color: #f4f4f4; padding: 20px;">
|
||||
<div style="max-width: 600px; background: #fff; padding: 20px; border-radius: 5px;">
|
||||
<h2>Jméno: {{name}}</h2>
|
||||
<br>
|
||||
<p>Zpráva: {{message}}</p>
|
||||
<br>
|
||||
<p>Email zákazníka: <a href="mailto:{{customer_email}}"></a>{{customer_email}}</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
7
home/templates/home/utilities/head.html
Normal file
@@ -0,0 +1,7 @@
|
||||
{% load static %}
|
||||
<meta name="description" content="Hledáte full-stack developera? Chcetě předělat starý web, lehkou opravu webovky nebo i velkou webovou aplikaci s responzivními prvky v realném čase? Tak to jste na správném místě">
|
||||
<meta name="keywords" content="vontor, web, web design, full-stack developer, tvorba webu, oprava webových stránek, responzivní web, webová aplikace, real-time web, redesign webu">
|
||||
<meta name="robots" content="index, follow">
|
||||
|
||||
<link rel="stylesheet" href="{% static "home/css/index.css" %}">
|
||||
<link rel="stylesheet" href="{% static "home/css/components/global/contact-me.css" %}">
|
||||
3
home/tests.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
12
home/urls.py
Normal file
@@ -0,0 +1,12 @@
|
||||
from django.urls import path
|
||||
from . import views
|
||||
|
||||
from django.contrib.sitemaps.views import sitemap
|
||||
#from .sitemaps import ProfileSitemap, CommunitySitemap, PostSitemap
|
||||
|
||||
sitemapURLs = ['home']
|
||||
|
||||
urlpatterns = [
|
||||
path('', views.home, name='home'),
|
||||
path('submit-contactme/', views.home, name='contactme'), #normálně bych redirectnul přes ajax na home ale kvůli googlu aby si toho všiml tak musím to nechat tak
|
||||
]
|
||||
55
home/views.py
Normal file
@@ -0,0 +1,55 @@
|
||||
from django.conf import settings
|
||||
from django.shortcuts import render
|
||||
from .models import AnonMessage
|
||||
|
||||
import json
|
||||
import requests
|
||||
from django.conf import settings
|
||||
from django.http import JsonResponse
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
|
||||
from django.core.mail import EmailMultiAlternatives
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.html import strip_tags
|
||||
|
||||
|
||||
from .forms import ContactMe
|
||||
|
||||
# Create your views here.
|
||||
def home(request):
|
||||
if request.method == "POST":
|
||||
form = ContactMe(request.POST)
|
||||
if form.is_valid():
|
||||
|
||||
send_email_contactme(request, form.cleaned_data["customer_email"], form.cleaned_data["message"], form.cleaned_data["customer_name"])
|
||||
|
||||
return JsonResponse({"success": True})
|
||||
else:
|
||||
return JsonResponse({"success": False, "errors": form.errors})
|
||||
|
||||
|
||||
#zprávy z chatu (posledníhc deset)
|
||||
last_messages = AnonMessage.get_last_messages(10, True)
|
||||
|
||||
for message in last_messages:
|
||||
message.time = message.time.strftime("%b. %d, %Y, %H:%M")
|
||||
|
||||
return render(request, 'home/index.html',{'last_messages':last_messages,'contactme_form': ContactMe()})
|
||||
|
||||
import logging
|
||||
from django.core.mail import send_mail
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def send_email_contactme(request, customer_email, message, name):
|
||||
subject = "vontor.cz - nový zákazník"
|
||||
recipient_email = customer_email
|
||||
context = f"Zákazník: {name}\nEmail: {customer_email}\n\nZpráva: {message}"
|
||||
|
||||
send_mail(
|
||||
subject,
|
||||
context,
|
||||
'"vontor.cz" <web@vontor.cz>',
|
||||
['brunovontor@gmail.com'],
|
||||
fail_silently=False,
|
||||
)
|
||||