Какой-то пиздец
This commit is contained in:
commit
39213ac57e
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -26,6 +26,15 @@ class Recall(models.Model):
|
||||
verbose_name_plural = 'Отзывы'
|
||||
ordering = ['time_create', 'title']
|
||||
|
||||
def get_seo_title(self):
|
||||
return f"Отзыв от {self.title} | Программист 1С"
|
||||
|
||||
def get_seo_description(self):
|
||||
if self.content:
|
||||
clean_content = self.content[:160].replace('\n', ' ').strip()
|
||||
return f"Отзыв о работе программиста 1С от {self.title}. {clean_content}..."
|
||||
return f"Отзыв клиента {self.title} о работе программиста 1С Николая Сердюк"
|
||||
|
||||
|
||||
class Competence(models.Model):
|
||||
title = models.CharField(max_length=255, verbose_name='Программист')
|
||||
@ -67,6 +76,23 @@ class Solution(models.Model):
|
||||
verbose_name_plural = 'Проекты'
|
||||
ordering = ['time_create', 'title']
|
||||
|
||||
def get_seo_title(self):
|
||||
"""Генерирует SEO-заголовок для проекта"""
|
||||
return f"Проект: {self.title} | Автоматизация 1С"
|
||||
|
||||
def get_seo_description(self):
|
||||
"""Генерирует SEO-описание для проекта"""
|
||||
if self.description:
|
||||
clean_desc = self.description[:160].replace('\n', ' ').strip()
|
||||
return f"Проект автоматизации: {self.title}. {clean_desc}..."
|
||||
return f"Реализация проекта {self.title} - программист 1С Николай Сердюк"
|
||||
|
||||
def get_meta_keywords(self):
|
||||
"""Автоматические ключевые слова для проекта"""
|
||||
base_keywords = ["проект 1С", "автоматизация 1С", "внедрение 1С"]
|
||||
title_words = self.title.lower().split()
|
||||
return base_keywords + title_words
|
||||
|
||||
|
||||
class Home(models.Model):
|
||||
title = models.CharField(max_length=255, verbose_name='Наименование')
|
||||
|
||||
@ -4,15 +4,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<title>{{title}} - Программист 1С</title>
|
||||
<title>{{title}}</title>
|
||||
<!-- Основные мета-теги -->
|
||||
<meta name="description" content="{% block meta_description %}Профессиональный программист 1С с более чем 10-летним опытом. Разработка, интеграция и оптимизация систем 1С.{% endblock %}">
|
||||
<meta name="keywords" content="{% block meta_keywords %}программист 1С, разработка 1С, интеграция 1С, оптимизация 1С, 1С предприятие{% endblock %}">
|
||||
<meta name="description" content="{% block meta_description %}{{ meta_description|default:'Профессиональный программист 1С с более чем 10-летним опытом. Разработка, интеграция и оптимизация систем 1С.' }}{% endblock %}">
|
||||
<meta name="keywords" content="{% block meta_keywords %}{{ meta_keywords|default:'программист 1С, разработка 1С, интеграция 1С, оптимизация 1С, 1С предприятие' }}{% endblock %}">
|
||||
<meta name="author" content="Николай Сердюк">
|
||||
|
||||
<!-- Open Graph для соцсетей -->
|
||||
<meta property="og:title" content="{{title}} - Программист 1С">
|
||||
<meta property="og:description" content="Профессиональный программист 1С с более чем 10-летним опытом">
|
||||
<meta property="og:title" content="{{title}}">
|
||||
<meta property="og:description" content="{% block og_description %}{{ meta_description|default:'Профессиональный программист 1С с более чем 10-летним опытом' }}{% endblock %}">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:url" content="{{ request.build_absolute_uri }}">
|
||||
<meta property="og:image" content="{% static 'programmer/images/og-image.jpg' %}">
|
||||
@ -20,8 +20,8 @@
|
||||
|
||||
<!-- Twitter Card -->
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="{{title}} - Программист 1С">
|
||||
<meta name="twitter:description" content="Профессиональный программист 1С с более чем 10-летним опытом">
|
||||
<meta name="twitter:title" content="{{title}}">
|
||||
<meta name="twitter:description" content="{% block twitter_description %}{{ meta_description|default:'Профессиональный программист 1С с более чем 10-летним опытом' }}{% endblock %}">
|
||||
<meta name="twitter:image" content="{% static 'programmer/images/og-image.jpg' %}">
|
||||
|
||||
<!-- Дополнительные SEO-теги -->
|
||||
@ -551,5 +551,28 @@
|
||||
{% block extra_js %}
|
||||
<!-- Дополнительные JS файлы для конкретных страниц -->
|
||||
{% endblock %}
|
||||
|
||||
<!-- В recall.html после основного контента -->
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "Review",
|
||||
"itemReviewed": {
|
||||
"@type": "Service",
|
||||
"name": "Услуги программиста 1С"
|
||||
},
|
||||
"author": {
|
||||
"@type": "Organization",
|
||||
"name": "ООО «РОВЕН-Регионы»"
|
||||
},
|
||||
"reviewRating": {
|
||||
"@type": "Rating",
|
||||
"ratingValue": "5",
|
||||
"bestRating": "5"
|
||||
},
|
||||
"datePublished": "2025-11-13",
|
||||
"description": "Выражаю благодарность программисту 1С Николаю Сердюк за профессиональную работу и качественное решение поставленных задач..."
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -20,7 +20,7 @@
|
||||
<div class="competence-scan-wrapper">
|
||||
<div class="competence-scan-container">
|
||||
<img src="{{ p.photo.url }}"
|
||||
alt="{{ p.title }}"
|
||||
alt="Сертификат 1С: {{ p.title }} - {{ p.content|striptags }}"
|
||||
class="competence-scan"
|
||||
onclick="openCompetenceModal('{{ p.photo.url }}', '{{ p.title }}')">
|
||||
<div class="scan-hint">
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
{% extends 'programmer/base.html' %}
|
||||
{% load django_bootstrap5 %}
|
||||
{% load static %}
|
||||
{% load seo_tags %}
|
||||
|
||||
{% block extra_css %}
|
||||
<link rel="stylesheet" href="{% static 'programmer/css/recall.css' %}">
|
||||
@ -8,13 +9,37 @@
|
||||
|
||||
{% block content %}
|
||||
<div class="page-header">
|
||||
<h1 class="page-title">Отзывы</h1>
|
||||
<p class="page-subtitle">Мнения клиентов и партнеров</p>
|
||||
<h1 class="page-title">Отзывы клиентов</h1>
|
||||
<p class="page-subtitle">Реальные отзывы о работе программиста 1С</p>
|
||||
</div>
|
||||
|
||||
<div class="recall-grid">
|
||||
{% for p in posts %}
|
||||
<div class="modern-card fade-in">
|
||||
|
||||
<!-- Добавляем микроразметку для отзыва -->
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "Review",
|
||||
"itemReviewed": {
|
||||
"@type": "Service",
|
||||
"name": "Услуги программиста 1С"
|
||||
},
|
||||
"author": {
|
||||
"@type": "Organization",
|
||||
"name": "{{ p.title }}"
|
||||
},
|
||||
"reviewRating": {
|
||||
"@type": "Rating",
|
||||
"ratingValue": "5",
|
||||
"bestRating": "5"
|
||||
},
|
||||
"datePublished": "{{ p.time_create|date:'Y-m-d' }}",
|
||||
"description": "{{ p.content|striptags|truncatewords:50 }}"
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="recall-item">
|
||||
<div class="recall-header">
|
||||
<div class="recall-info">
|
||||
|
||||
@ -6,6 +6,7 @@ Sitemap: {{ request.scheme }}://{{ request.get_host }}/sitemap.xml
|
||||
|
||||
# Запрещаем служебные разделы
|
||||
Disallow: /admin/
|
||||
Disallow: /media/cache/
|
||||
Disallow: /static/admin/
|
||||
Disallow: /callback/
|
||||
Disallow: /api/
|
||||
|
||||
@ -1,21 +1,40 @@
|
||||
{% extends 'programmer/base.html' %}
|
||||
{% load django_bootstrap5 %}
|
||||
{% load static %}
|
||||
{% load seo_tags %}
|
||||
|
||||
{% block extra_css %}
|
||||
<link rel="stylesheet" href="{% static 'programmer/css/solution-accordion.css' %}">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>{{title}}</h1>
|
||||
<div class="page-header">
|
||||
<h1 class="page-title">Проекты автоматизации 1С</h1>
|
||||
<p class="page-subtitle">Реализованные решения и кейсы по автоматизации бизнес-процессов</p>
|
||||
</div>
|
||||
|
||||
<div class="improved-list">
|
||||
{% autoescape off %}
|
||||
{% for p in posts %}
|
||||
<li class="fade-in">
|
||||
<li class="modern-card fade-in">
|
||||
<div class="content-card">
|
||||
<h2>{{p.title}}</h2>
|
||||
|
||||
<!-- Добавляем микроразметку для проекта -->
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "CreativeWork",
|
||||
"name": "{{ p.title }}",
|
||||
"description": "{{ p.description|striptags|truncatewords:30 }}",
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "Николай Сердюк"
|
||||
},
|
||||
"datePublished": "{{ p.time_create|date:'Y-m-d' }}"
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="solution-accordion">
|
||||
<div class="accordion-item">
|
||||
<div class="accordion-header" onclick="toggleAccordion(this)">
|
||||
@ -52,6 +71,13 @@
|
||||
<p class="first">Опубликовано: {{p.time_create|date:"d.m.Y"}}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% empty %}
|
||||
<div class="modern-card text-center fade-in">
|
||||
<h3>🚀 Проекты в разработке</h3>
|
||||
<p class="card-subtitle">Скоро здесь появятся новые кейсы автоматизации</p>
|
||||
</div>
|
||||
|
||||
</li>
|
||||
{% endfor %}
|
||||
{% endautoescape %}
|
||||
|
||||
Binary file not shown.
21
OneCprogsite/programmer/templatetags/seo_tags.py
Normal file
21
OneCprogsite/programmer/templatetags/seo_tags.py
Normal file
@ -0,0 +1,21 @@
|
||||
from django import template
|
||||
from django.utils.html import strip_tags
|
||||
|
||||
register = template.Library()
|
||||
|
||||
@register.simple_tag
|
||||
def generate_meta_description(obj, default=""):
|
||||
"""Генерирует meta description для объектов"""
|
||||
if hasattr(obj, 'get_seo_description'):
|
||||
return obj.get_seo_description()
|
||||
elif hasattr(obj, 'content'):
|
||||
clean_content = strip_tags(obj.content)[:160]
|
||||
return clean_content + '...' if len(clean_content) > 160 else clean_content
|
||||
return default
|
||||
|
||||
@register.simple_tag
|
||||
def generate_meta_keywords(obj, default=""):
|
||||
"""Генерирует meta keywords для объектов"""
|
||||
if hasattr(obj, 'get_meta_keywords'):
|
||||
return ', '.join(obj.get_meta_keywords())
|
||||
return default
|
||||
@ -107,9 +107,9 @@ def index(request):
|
||||
context = {
|
||||
'posts': posts,
|
||||
'menu': menu,
|
||||
'title': "Главная страница",
|
||||
'meta_description': "Профессиональный программист 1С с более чем 10-летним опытом. Разработка, интеграция и оптимизация систем 1С. Закажите консультацию.",
|
||||
'meta_keywords': "программист 1С, разработка 1С, интеграция 1С, оптимизация 1С, 1С предприятие 8.3",
|
||||
'title': "Программист 1С Николай Сердюк - разработка и сопровождение",
|
||||
'meta_description': "Профессиональный программист 1С с более чем 10-летним опытом. Разработка, доработка, обновление и интеграция систем 1С. Сопровождение 1С.",
|
||||
'meta_keywords': "программист 1С, разработка 1С, обновление 1С, сопровождение 1С, интеграция 1С, доработка 1С, 1С предприятие 8.3",
|
||||
'form': CallbackForm()
|
||||
}
|
||||
return render(request, 'programmer/index.html', context=context)
|
||||
@ -119,9 +119,9 @@ def index(request):
|
||||
def about(request):
|
||||
context = {
|
||||
'menu': menu,
|
||||
'title': "Обо мне - Программист 1С",
|
||||
'meta_description': "Николай Сердюк - профессиональный программист 1С с более чем 10-летним опытом. Разработка, интеграция, оптимизация бизнес-процессов.",
|
||||
'meta_keywords': "программист 1С Николай Сердюк, опыт работы 1С, компетенции 1С, проекты 1С"
|
||||
'title': "Программист 1С Николай Сердюк - 10+ лет опыта | Услуги 1С",
|
||||
'meta_description': "Николай Сердюк - сертифицированный программист 1С с 10+ лет опыта. Специализация: обновление 1С, разработка под ключ, интеграция, миграция с 1С 7.7.",
|
||||
'meta_keywords': "программист 1С Николай Сердюк, обновление 1С, разработка 1С под ключ, интеграция 1С, сертифицированный 1С, миграция 1С 7.7"
|
||||
}
|
||||
return render(request, 'programmer/about.html', context=context)
|
||||
|
||||
@ -132,7 +132,9 @@ def solution(request):
|
||||
context = {
|
||||
'posts': posts,
|
||||
'menu': menu,
|
||||
'title': "Проекты"
|
||||
'meta_description': "Реализованные проекты по автоматизации 1С: складской учет с ТСД, интеграция с оборудованием, миграция с 1С 7.7. Примеры работ и кейсы.",
|
||||
'meta_keywords': "проекты 1С, автоматизация склада 1С, интеграция ТСД 1С, миграция 1С 7.7, кейсы 1С, примеры работ 1С",
|
||||
'title': "Проекты автоматизации 1С | Реализованные кейсы и решения",
|
||||
}
|
||||
return render(request, 'programmer/solution.html', context=context)
|
||||
|
||||
@ -143,7 +145,9 @@ def ability(request):
|
||||
context = {
|
||||
'posts': posts,
|
||||
'menu': menu,
|
||||
'title': "Компетенции"
|
||||
'title': "Сертификаты и компетенции 1С | Программист 1С Николай Сердюк",
|
||||
'meta_description': "Сертификаты 1С: Профессионал по платформе 8.3 и БП 3.0. Подтвержденная квалификация программиста 1С с сертификатами фирмы 1С.",
|
||||
'meta_keywords': "сертификаты 1С, 1С профессионал, компетенции 1С, квалификация программиста 1С, сертифицированный специалист 1С"
|
||||
}
|
||||
return render(request, 'programmer/competence.html', context=context)
|
||||
|
||||
@ -154,7 +158,9 @@ def recall(request):
|
||||
context = {
|
||||
'posts': posts,
|
||||
'menu': menu,
|
||||
'title': "Отзывы"
|
||||
'title': "Отзывы клиентов о работе программиста 1С | Реальные кейсы",
|
||||
'meta_description': "Реальные отзывы клиентов о работе программиста 1С Николая Сердюка. Отзывы от ООО «РОВЕН-Регионы» и других компаний.",
|
||||
'meta_keywords': "отзывы программист 1С, рекомендации 1С, отзывы клиентов 1С, реальные кейсы 1С, отзыв ООО РОВЕН"
|
||||
}
|
||||
return render(request, 'programmer/recall.html', context=context)
|
||||
|
||||
|
||||
@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @fileOverview CSS for jquery-autocomplete, the jQuery Autocompleter
|
||||
* @author <a href="mailto:dylan@dyve.net">Dylan Verheul</a>
|
||||
* @license MIT | GPL | Apache 2.0, see LICENSE.txt
|
||||
* @see https://github.com/dyve/jquery-autocomplete
|
||||
*/
|
||||
.acResults {
|
||||
padding: 0px;
|
||||
border: 1px solid WindowFrame;
|
||||
background-color: Window;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.acResults ul {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
list-style-position: outside;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.acResults ul li {
|
||||
margin: 0px;
|
||||
padding: 2px 5px;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
font: menu;
|
||||
font-size: 12px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.acLoading {
|
||||
background : url('../img/indicator.gif') right center no-repeat;
|
||||
}
|
||||
|
||||
.acSelect {
|
||||
background-color: Highlight;
|
||||
color: HighlightText;
|
||||
}
|
||||
BIN
OneCprogsite/static/django_extensions/img/indicator.gif
Normal file
BIN
OneCprogsite/static/django_extensions/img/indicator.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
116
OneCprogsite/static/django_extensions/js/jquery.ajaxQueue.js
Normal file
116
OneCprogsite/static/django_extensions/js/jquery.ajaxQueue.js
Normal file
@ -0,0 +1,116 @@
|
||||
/**
|
||||
* Ajax Queue Plugin
|
||||
*/
|
||||
|
||||
/**
|
||||
|
||||
<script>
|
||||
$(function(){
|
||||
jQuery.ajaxQueue({
|
||||
url: "test.php",
|
||||
success: function(html){ jQuery("ul").append(html); }
|
||||
});
|
||||
jQuery.ajaxQueue({
|
||||
url: "test.php",
|
||||
success: function(html){ jQuery("ul").append(html); }
|
||||
});
|
||||
jQuery.ajaxSync({
|
||||
url: "test.php",
|
||||
success: function(html){ jQuery("ul").append("<b>"+html+"</b>"); }
|
||||
});
|
||||
jQuery.ajaxSync({
|
||||
url: "test.php",
|
||||
success: function(html){ jQuery("ul").append("<b>"+html+"</b>"); }
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<ul style="position: absolute; top: 5px; right: 5px;"></ul>
|
||||
|
||||
*/
|
||||
/*
|
||||
* Queued Ajax requests.
|
||||
* A new Ajax request won't be started until the previous queued
|
||||
* request has finished.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Synced Ajax requests.
|
||||
* The Ajax request will happen as soon as you call this method, but
|
||||
* the callbacks (success/error/complete) won't fire until all previous
|
||||
* synced requests have been completed.
|
||||
*/
|
||||
|
||||
|
||||
(function(jQuery) {
|
||||
|
||||
var ajax = jQuery.ajax;
|
||||
|
||||
var pendingRequests = {};
|
||||
|
||||
var synced = [];
|
||||
var syncedData = [];
|
||||
|
||||
jQuery.ajax = function(settings) {
|
||||
// create settings for compatibility with ajaxSetup
|
||||
settings = jQuery.extend(settings, jQuery.extend({}, jQuery.ajaxSettings, settings));
|
||||
|
||||
var port = settings.port;
|
||||
|
||||
switch(settings.mode) {
|
||||
case "abort":
|
||||
if ( pendingRequests[port] ) {
|
||||
pendingRequests[port].abort();
|
||||
}
|
||||
return pendingRequests[port] = ajax.apply(this, arguments);
|
||||
case "queue":
|
||||
var _old = settings.complete;
|
||||
settings.complete = function(){
|
||||
if ( _old )
|
||||
_old.apply( this, arguments );
|
||||
jQuery([ajax]).dequeue("ajax" + port );;
|
||||
};
|
||||
|
||||
jQuery([ ajax ]).queue("ajax" + port, function(){
|
||||
ajax( settings );
|
||||
});
|
||||
return;
|
||||
case "sync":
|
||||
var pos = synced.length;
|
||||
|
||||
synced[ pos ] = {
|
||||
error: settings.error,
|
||||
success: settings.success,
|
||||
complete: settings.complete,
|
||||
done: false
|
||||
};
|
||||
|
||||
syncedData[ pos ] = {
|
||||
error: [],
|
||||
success: [],
|
||||
complete: []
|
||||
};
|
||||
|
||||
settings.error = function(){ syncedData[ pos ].error = arguments; };
|
||||
settings.success = function(){ syncedData[ pos ].success = arguments; };
|
||||
settings.complete = function(){
|
||||
syncedData[ pos ].complete = arguments;
|
||||
synced[ pos ].done = true;
|
||||
|
||||
if ( pos == 0 || !synced[ pos-1 ] )
|
||||
for ( var i = pos; i < synced.length && synced[i].done; i++ ) {
|
||||
if ( synced[i].error ) synced[i].error.apply( jQuery, syncedData[i].error );
|
||||
if ( synced[i].success ) synced[i].success.apply( jQuery, syncedData[i].success );
|
||||
if ( synced[i].complete ) synced[i].complete.apply( jQuery, syncedData[i].complete );
|
||||
|
||||
synced[i] = null;
|
||||
syncedData[i] = null;
|
||||
}
|
||||
};
|
||||
}
|
||||
return ajax.apply(this, arguments);
|
||||
};
|
||||
|
||||
})((typeof window.jQuery == 'undefined' && typeof window.django != 'undefined')
|
||||
? django.jQuery
|
||||
: jQuery
|
||||
);
|
||||
1152
OneCprogsite/static/django_extensions/js/jquery.autocomplete.js
Normal file
1152
OneCprogsite/static/django_extensions/js/jquery.autocomplete.js
Normal file
File diff suppressed because it is too large
Load Diff
39
OneCprogsite/static/django_extensions/js/jquery.bgiframe.js
Normal file
39
OneCprogsite/static/django_extensions/js/jquery.bgiframe.js
Normal file
@ -0,0 +1,39 @@
|
||||
/*! Copyright (c) 2010 Brandon Aaron (http://brandon.aaron.sh/)
|
||||
* Licensed under the MIT License (LICENSE.txt).
|
||||
*
|
||||
* Version 2.1.2
|
||||
*/
|
||||
|
||||
(function($){
|
||||
|
||||
$.fn.bgiframe = ($.browser.msie && /msie 6\.0/i.test(navigator.userAgent) ? function(s) {
|
||||
s = $.extend({
|
||||
top : 'auto', // auto == .currentStyle.borderTopWidth
|
||||
left : 'auto', // auto == .currentStyle.borderLeftWidth
|
||||
width : 'auto', // auto == offsetWidth
|
||||
height : 'auto', // auto == offsetHeight
|
||||
opacity : true,
|
||||
src : 'javascript:false;'
|
||||
}, s);
|
||||
var html = '<iframe class="bgiframe"frameborder="0"tabindex="-1"src="'+s.src+'"'+
|
||||
'style="display:block;position:absolute;z-index:-1;'+
|
||||
(s.opacity !== false?'filter:Alpha(Opacity=\'0\');':'')+
|
||||
'top:'+(s.top=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderTopWidth)||0)*-1)+\'px\')':prop(s.top))+';'+
|
||||
'left:'+(s.left=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderLeftWidth)||0)*-1)+\'px\')':prop(s.left))+';'+
|
||||
'width:'+(s.width=='auto'?'expression(this.parentNode.offsetWidth+\'px\')':prop(s.width))+';'+
|
||||
'height:'+(s.height=='auto'?'expression(this.parentNode.offsetHeight+\'px\')':prop(s.height))+';'+
|
||||
'"/>';
|
||||
return this.each(function() {
|
||||
if ( $(this).children('iframe.bgiframe').length === 0 )
|
||||
this.insertBefore( document.createElement(html), this.firstChild );
|
||||
});
|
||||
} : function() { return this; });
|
||||
|
||||
// old alias
|
||||
$.fn.bgIframe = $.fn.bgiframe;
|
||||
|
||||
function prop(n) {
|
||||
return n && n.constructor === Number ? n + 'px' : n;
|
||||
}
|
||||
|
||||
})((typeof window.jQuery == 'undefined' && typeof window.django != 'undefined') ? django.jQuery : jQuery);
|
||||
6
OneCprogsite/static/programmer/css/bootstrap.min.css
vendored
Normal file
6
OneCprogsite/static/programmer/css/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
299
OneCprogsite/static/programmer/css/competence.css
Normal file
299
OneCprogsite/static/programmer/css/competence.css
Normal file
@ -0,0 +1,299 @@
|
||||
/* competence.css - Стили для страницы компетенций */
|
||||
|
||||
/* Основные стили для страницы компетенций */
|
||||
.competence-item {
|
||||
display: flex;
|
||||
gap: 2rem;
|
||||
align-items: flex-start;
|
||||
padding: 2rem;
|
||||
background: var(--bg-card);
|
||||
border-radius: var(--radius-xl);
|
||||
box-shadow: var(--shadow-lg);
|
||||
border-left: 4px solid var(--secondary);
|
||||
transition: var(--transition);
|
||||
border: 1px solid var(--border-light);
|
||||
}
|
||||
|
||||
.competence-item:hover {
|
||||
transform: translateX(8px);
|
||||
box-shadow: var(--shadow-xl);
|
||||
border-color: var(--primary-light);
|
||||
}
|
||||
|
||||
.competence-scan-wrapper {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.competence-scan-container {
|
||||
width: 280px;
|
||||
cursor: pointer;
|
||||
border-radius: var(--radius-lg);
|
||||
overflow: hidden;
|
||||
border: 2px solid var(--border-light);
|
||||
transition: var(--transition);
|
||||
position: relative;
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
.competence-scan-container:hover {
|
||||
transform: translateY(-4px) scale(1.02);
|
||||
box-shadow: var(--shadow-xl);
|
||||
border-color: var(--primary);
|
||||
}
|
||||
|
||||
.competence-scan {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
transition: var(--transition);
|
||||
}
|
||||
|
||||
.competence-content {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.competence-title {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: 1rem;
|
||||
background: var(--gradient-primary);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
}
|
||||
|
||||
.competence-description {
|
||||
line-height: 1.7;
|
||||
font-size: 1.05rem;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.competence-description p {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.competence-description p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.scan-hint {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: linear-gradient(transparent, rgba(0,0,0,0.8));
|
||||
color: white;
|
||||
padding: 1rem;
|
||||
text-align: center;
|
||||
opacity: 0;
|
||||
transition: var(--transition);
|
||||
transform: translateY(10px);
|
||||
}
|
||||
|
||||
.competence-scan-container:hover .scan-hint {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
/* Стили для модального окна с изображением компетенций */
|
||||
.modal.competence-modal {
|
||||
background-color: rgba(15, 19, 31, 0.95);
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.modal.competence-modal .modal-content {
|
||||
background: transparent;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
max-width: 95vw;
|
||||
max-height: 95vh;
|
||||
margin: 2% auto;
|
||||
}
|
||||
|
||||
.modal.competence-modal .modal-header {
|
||||
background: var(--bg-card);
|
||||
border-bottom: 2px solid var(--border-light);
|
||||
padding: 1.5rem 2rem;
|
||||
}
|
||||
|
||||
.modal.competence-modal .modal-header h3 {
|
||||
margin: 0;
|
||||
color: var(--text-primary);
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
background: var(--gradient-primary);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
}
|
||||
|
||||
.modal.competence-modal .modal-body {
|
||||
padding: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.modal-image {
|
||||
max-width: 90vw;
|
||||
max-height: 80vh;
|
||||
width: auto;
|
||||
height: auto;
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
border-radius: var(--radius-md);
|
||||
box-shadow: var(--shadow-xl);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
/* Анимации для модального окна */
|
||||
.modal.competence-modal {
|
||||
transition: opacity 0.3s ease;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.modal.competence-modal.active {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.modal.competence-modal .modal-content {
|
||||
transform: scale(0.7);
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.modal.competence-modal.active .modal-content {
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
/* Улучшенные тени и границы */
|
||||
.competence-scan-container {
|
||||
border: 2px solid var(--border-light);
|
||||
box-shadow: var(--shadow-lg);
|
||||
}
|
||||
|
||||
.competence-scan-container:hover {
|
||||
border-color: var(--primary-light);
|
||||
box-shadow: var(--shadow-xl);
|
||||
}
|
||||
|
||||
/* Адаптивность для мобильных устройств */
|
||||
@media (max-width: 768px) {
|
||||
.competence-item {
|
||||
flex-direction: column;
|
||||
padding: 1.5rem;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.competence-scan-container {
|
||||
width: 100%;
|
||||
max-width: 300px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.competence-title {
|
||||
font-size: 1.375rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.modal-image {
|
||||
max-width: 95vw;
|
||||
max-height: 70vh;
|
||||
}
|
||||
|
||||
.modal.competence-modal .modal-content {
|
||||
margin: 10% auto;
|
||||
}
|
||||
|
||||
.modal.competence-modal .modal-header {
|
||||
padding: 1rem 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.competence-item {
|
||||
padding: 1.25rem;
|
||||
}
|
||||
|
||||
.competence-scan-container {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.competence-title {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.modal.competence-modal .modal-content {
|
||||
margin: 5% auto;
|
||||
max-width: 98vw;
|
||||
}
|
||||
|
||||
.modal.competence-modal .modal-body {
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.modal.competence-modal .modal-header {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.modal.competence-modal .modal-header h3 {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Стили для светлой темы */
|
||||
@media (prefers-color-scheme: light) {
|
||||
.modal.competence-modal {
|
||||
background-color: rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
.modal.competence-modal .modal-header {
|
||||
background: var(--bg-primary);
|
||||
}
|
||||
|
||||
.scan-hint {
|
||||
background: linear-gradient(transparent, rgba(0,0,0,0.7));
|
||||
}
|
||||
|
||||
.competence-item {
|
||||
background: var(--bg-primary);
|
||||
}
|
||||
|
||||
.competence-description {
|
||||
color: var(--text-primary);
|
||||
}
|
||||
}
|
||||
|
||||
/* Улучшенные стили для сетки компетенций */
|
||||
.competence-grid {
|
||||
display: grid;
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
.competence-grid .modern-card {
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.competence-grid .modern-card::before {
|
||||
height: 4px;
|
||||
background: var(--gradient-secondary);
|
||||
}
|
||||
|
||||
/* Анимации появления */
|
||||
.fade-in {
|
||||
animation: fadeInUp 0.8s ease-out;
|
||||
}
|
||||
|
||||
@keyframes fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(40px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
228
OneCprogsite/static/programmer/css/recall.css
Normal file
228
OneCprogsite/static/programmer/css/recall.css
Normal file
@ -0,0 +1,228 @@
|
||||
/* recall.css - Стили для страницы отзывов */
|
||||
|
||||
/* Основные стили для страницы отзывов */
|
||||
.recall-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.recall-content {
|
||||
display: flex;
|
||||
gap: 2rem;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.recall-scan-wrapper {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.recall-scan-container {
|
||||
width: 280px;
|
||||
cursor: pointer;
|
||||
border-radius: var(--radius-lg);
|
||||
overflow: hidden;
|
||||
border: 2px solid var(--border-light);
|
||||
transition: var(--transition);
|
||||
position: relative;
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
.recall-scan-container:hover {
|
||||
transform: translateY(-4px) scale(1.02);
|
||||
box-shadow: var(--shadow-xl);
|
||||
border-color: var(--primary);
|
||||
}
|
||||
|
||||
.recall-scan {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
transition: var(--transition);
|
||||
}
|
||||
|
||||
.recall-text {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
line-height: 1.7;
|
||||
font-size: 1.05rem;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.recall-text p {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.recall-text p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.scan-hint {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: linear-gradient(transparent, rgba(0,0,0,0.8));
|
||||
color: white;
|
||||
padding: 1rem;
|
||||
text-align: center;
|
||||
opacity: 0;
|
||||
transition: var(--transition);
|
||||
transform: translateY(10px);
|
||||
}
|
||||
|
||||
.recall-scan-container:hover .scan-hint {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
/* Стили для модального окна с изображением */
|
||||
.modal.image-modal {
|
||||
background-color: rgba(15, 19, 31, 0.95);
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.modal.image-modal .modal-content {
|
||||
background: transparent;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
max-width: 95vw;
|
||||
max-height: 95vh;
|
||||
margin: 2% auto;
|
||||
}
|
||||
|
||||
.modal.image-modal .modal-header {
|
||||
background: var(--bg-card);
|
||||
border-bottom: 2px solid var(--border-light);
|
||||
padding: 1.5rem 2rem;
|
||||
}
|
||||
|
||||
.modal.image-modal .modal-header h3 {
|
||||
margin: 0;
|
||||
color: var(--text-primary);
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
background: var(--gradient-primary);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
}
|
||||
|
||||
.modal.image-modal .modal-body {
|
||||
padding: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.modal-image {
|
||||
max-width: 90vw;
|
||||
max-height: 80vh;
|
||||
width: auto;
|
||||
height: auto;
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
border-radius: var(--radius-md);
|
||||
box-shadow: var(--shadow-xl);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
/* Анимации для модального окна */
|
||||
.modal.image-modal {
|
||||
transition: opacity 0.3s ease;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.modal.image-modal.active {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.modal.image-modal .modal-content {
|
||||
transform: scale(0.7);
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.modal.image-modal.active .modal-content {
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
/* Улучшенные тени и границы */
|
||||
.recall-scan-container {
|
||||
border: 2px solid var(--border-light);
|
||||
box-shadow: var(--shadow-lg);
|
||||
}
|
||||
|
||||
.recall-scan-container:hover {
|
||||
border-color: var(--primary-light);
|
||||
box-shadow: var(--shadow-xl);
|
||||
}
|
||||
|
||||
/* Адаптивность для мобильных устройств */
|
||||
@media (max-width: 768px) {
|
||||
.recall-content {
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.recall-scan-container {
|
||||
width: 100%;
|
||||
max-width: 300px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.recall-scan-wrapper {
|
||||
order: -1;
|
||||
}
|
||||
|
||||
.modal-image {
|
||||
max-width: 95vw;
|
||||
max-height: 70vh;
|
||||
}
|
||||
|
||||
.modal.image-modal .modal-content {
|
||||
margin: 10% auto;
|
||||
}
|
||||
|
||||
.modal.image-modal .modal-header {
|
||||
padding: 1rem 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.recall-scan-container {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.modal.image-modal .modal-content {
|
||||
margin: 5% auto;
|
||||
max-width: 98vw;
|
||||
}
|
||||
|
||||
.modal.image-modal .modal-body {
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.modal.image-modal .modal-header {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.modal.image-modal .modal-header h3 {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Стили для светлой темы */
|
||||
@media (prefers-color-scheme: light) {
|
||||
.modal.image-modal {
|
||||
background-color: rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
.modal.image-modal .modal-header {
|
||||
background: var(--bg-primary);
|
||||
}
|
||||
|
||||
.scan-hint {
|
||||
background: linear-gradient(transparent, rgba(0,0,0,0.7));
|
||||
}
|
||||
}
|
||||
67
OneCprogsite/static/programmer/css/solution-accordion.css
Normal file
67
OneCprogsite/static/programmer/css/solution-accordion.css
Normal file
@ -0,0 +1,67 @@
|
||||
/* solution-accordion.css */
|
||||
.solution-accordion {
|
||||
margin: 2rem 0;
|
||||
}
|
||||
|
||||
.accordion-item {
|
||||
background: var(--bg-primary);
|
||||
border-radius: var(--radius-lg);
|
||||
margin-bottom: 1rem;
|
||||
border: 2px solid var(--border-light);
|
||||
overflow: hidden;
|
||||
transition: var(--transition);
|
||||
}
|
||||
|
||||
.accordion-item:hover {
|
||||
border-color: var(--primary-light);
|
||||
}
|
||||
|
||||
.accordion-header {
|
||||
padding: 1.5rem;
|
||||
background: var(--gradient-primary);
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
font-size: 1.125rem;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
transition: var(--transition);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.accordion-header:hover {
|
||||
background: var(--primary-dark);
|
||||
}
|
||||
|
||||
.accordion-content {
|
||||
padding: 0;
|
||||
background: var(--bg-card);
|
||||
line-height: 1.7;
|
||||
color: var(--text-secondary);
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.accordion-content.active {
|
||||
padding: 1.5rem;
|
||||
max-height: 5000px;
|
||||
}
|
||||
|
||||
.accordion-icon {
|
||||
transition: transform 0.3s ease;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
.accordion-header.active .accordion-icon {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.accordion-content p {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.accordion-content p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
1007
OneCprogsite/static/programmer/css/styles.css
Normal file
1007
OneCprogsite/static/programmer/css/styles.css
Normal file
File diff suppressed because it is too large
Load Diff
1473
OneCprogsite/static/programmer/css/styles_dark.css
Normal file
1473
OneCprogsite/static/programmer/css/styles_dark.css
Normal file
File diff suppressed because it is too large
Load Diff
1406
OneCprogsite/static/programmer/css/styles_w.css
Normal file
1406
OneCprogsite/static/programmer/css/styles_w.css
Normal file
File diff suppressed because it is too large
Load Diff
73
OneCprogsite/static/programmer/js/competence.js
Normal file
73
OneCprogsite/static/programmer/js/competence.js
Normal file
@ -0,0 +1,73 @@
|
||||
// competence.js - Скрипты для страницы компетенций
|
||||
function openCompetenceModal(imageUrl, title) {
|
||||
console.log('Opening competence modal with:', imageUrl);
|
||||
const modal = document.getElementById('competenceModal');
|
||||
const modalImg = document.getElementById('competenceModalImage');
|
||||
const modalTitle = document.getElementById('competenceModalTitle');
|
||||
|
||||
if (modal && modalImg) {
|
||||
modal.style.display = "block";
|
||||
modalImg.src = imageUrl;
|
||||
if (title && modalTitle) {
|
||||
modalTitle.textContent = title;
|
||||
}
|
||||
|
||||
// Добавляем класс для анимации
|
||||
setTimeout(() => {
|
||||
modal.classList.add('active');
|
||||
}, 10);
|
||||
|
||||
// Подстраиваем размер изображения
|
||||
adjustCompetenceModalImageSize();
|
||||
}
|
||||
}
|
||||
|
||||
function closeCompetenceModal() {
|
||||
const modal = document.getElementById('competenceModal');
|
||||
if (modal) {
|
||||
modal.classList.remove('active');
|
||||
setTimeout(() => {
|
||||
modal.style.display = "none";
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
|
||||
function adjustCompetenceModalImageSize() {
|
||||
const modalImg = document.getElementById('competenceModalImage');
|
||||
|
||||
if (modalImg) {
|
||||
const maxWidth = window.innerWidth * 0.9;
|
||||
const maxHeight = window.innerHeight * 0.8;
|
||||
|
||||
modalImg.style.maxWidth = `${maxWidth}px`;
|
||||
modalImg.style.maxHeight = `${maxHeight}px`;
|
||||
}
|
||||
}
|
||||
|
||||
// Инициализация после загрузки DOM
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Закрытие модального окна при клике вне изображения
|
||||
document.addEventListener('click', function(event) {
|
||||
const modal = document.getElementById('competenceModal');
|
||||
if (event.target === modal) {
|
||||
closeCompetenceModal();
|
||||
}
|
||||
});
|
||||
|
||||
// Закрытие по ESC
|
||||
document.addEventListener('keydown', function(event) {
|
||||
if (event.key === 'Escape') {
|
||||
closeCompetenceModal();
|
||||
}
|
||||
});
|
||||
|
||||
// Адаптация размера изображения при изменении размера окна
|
||||
window.addEventListener('resize', function() {
|
||||
const modalImg = document.getElementById('competenceModalImage');
|
||||
if (modalImg && modalImg.src) {
|
||||
adjustCompetenceModalImageSize();
|
||||
}
|
||||
});
|
||||
|
||||
console.log('Competence page scripts initialized');
|
||||
});
|
||||
94
OneCprogsite/static/programmer/js/mobile-menu.js
Normal file
94
OneCprogsite/static/programmer/js/mobile-menu.js
Normal file
@ -0,0 +1,94 @@
|
||||
// Mobile Menu Script
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
console.log('Mobile menu script loaded'); // Для отладки
|
||||
|
||||
const mobileMenuBtn = document.getElementById('mobileMenuBtn');
|
||||
const mobileMenuClose = document.getElementById('mobileMenuClose');
|
||||
const mobileMenuOverlay = document.getElementById('mobileMenuOverlay');
|
||||
const mobileMenu = document.getElementById('mobileMenu');
|
||||
const mobileThemeToggle = document.getElementById('mobile-theme-toggle');
|
||||
const mainThemeToggle = document.getElementById('theme-toggle');
|
||||
|
||||
// Проверяем, что элементы существуют
|
||||
if (!mobileMenuBtn || !mobileMenu) {
|
||||
console.error('Mobile menu elements not found');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Mobile menu elements found:', {
|
||||
mobileMenuBtn,
|
||||
mobileMenuClose,
|
||||
mobileMenuOverlay,
|
||||
mobileMenu,
|
||||
mobileThemeToggle,
|
||||
mainThemeToggle
|
||||
});
|
||||
|
||||
// Открытие мобильного меню
|
||||
mobileMenuBtn.addEventListener('click', function() {
|
||||
console.log('Opening mobile menu');
|
||||
mobileMenu.classList.add('active');
|
||||
mobileMenuOverlay.style.display = 'block';
|
||||
document.body.style.overflow = 'hidden';
|
||||
});
|
||||
|
||||
// Закрытие мобильного меню
|
||||
function closeMobileMenu() {
|
||||
console.log('Closing mobile menu');
|
||||
mobileMenu.classList.remove('active');
|
||||
mobileMenuOverlay.style.display = 'none';
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
|
||||
if (mobileMenuClose) {
|
||||
mobileMenuClose.addEventListener('click', closeMobileMenu);
|
||||
}
|
||||
|
||||
if (mobileMenuOverlay) {
|
||||
mobileMenuOverlay.addEventListener('click', closeMobileMenu);
|
||||
}
|
||||
|
||||
// Закрытие меню при клике на ссылку
|
||||
const mobileNavLinks = document.querySelectorAll('.mobile-nav-link');
|
||||
mobileNavLinks.forEach(link => {
|
||||
link.addEventListener('click', closeMobileMenu);
|
||||
});
|
||||
|
||||
// Синхронизация переключателей темы
|
||||
function syncThemeToggles() {
|
||||
if (mobileThemeToggle && mainThemeToggle) {
|
||||
mobileThemeToggle.checked = mainThemeToggle.checked;
|
||||
}
|
||||
}
|
||||
|
||||
if (mainThemeToggle) {
|
||||
mainThemeToggle.addEventListener('change', function() {
|
||||
console.log('Main theme toggle changed:', this.checked);
|
||||
syncThemeToggles();
|
||||
});
|
||||
}
|
||||
|
||||
if (mobileThemeToggle) {
|
||||
mobileThemeToggle.addEventListener('change', function() {
|
||||
console.log('Mobile theme toggle changed:', this.checked);
|
||||
if (mainThemeToggle) {
|
||||
mainThemeToggle.checked = this.checked;
|
||||
// Триггерим событие change
|
||||
const event = new Event('change');
|
||||
mainThemeToggle.dispatchEvent(event);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Инициализация синхронизации
|
||||
syncThemeToggles();
|
||||
|
||||
// Закрытие меню по ESC
|
||||
document.addEventListener('keydown', function(event) {
|
||||
if (event.key === 'Escape') {
|
||||
closeMobileMenu();
|
||||
}
|
||||
});
|
||||
|
||||
console.log('Mobile menu script initialized successfully');
|
||||
});
|
||||
74
OneCprogsite/static/programmer/js/recall.js
Normal file
74
OneCprogsite/static/programmer/js/recall.js
Normal file
@ -0,0 +1,74 @@
|
||||
// recall.js - Скрипты для страницы отзывов
|
||||
function openModal(imageUrl, title) {
|
||||
console.log('Opening modal with:', imageUrl);
|
||||
const modal = document.getElementById('imageModal');
|
||||
const modalImg = document.getElementById('modalImage');
|
||||
const modalTitle = document.getElementById('modalTitle');
|
||||
|
||||
if (modal && modalImg) {
|
||||
modal.style.display = "block";
|
||||
modalImg.src = imageUrl;
|
||||
if (title && modalTitle) {
|
||||
modalTitle.textContent = title;
|
||||
}
|
||||
|
||||
// Добавляем класс для анимации
|
||||
setTimeout(() => {
|
||||
modal.classList.add('active');
|
||||
}, 10);
|
||||
|
||||
// Подстраиваем размер изображения
|
||||
adjustModalImageSize();
|
||||
}
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
const modal = document.getElementById('imageModal');
|
||||
if (modal) {
|
||||
modal.classList.remove('active');
|
||||
setTimeout(() => {
|
||||
modal.style.display = "none";
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
|
||||
function adjustModalImageSize() {
|
||||
const modalImg = document.getElementById('modalImage');
|
||||
const modalContent = document.querySelector('.modal-content');
|
||||
|
||||
if (modalImg && modalContent) {
|
||||
const maxWidth = window.innerWidth * 0.9;
|
||||
const maxHeight = window.innerHeight * 0.8;
|
||||
|
||||
modalImg.style.maxWidth = `${maxWidth}px`;
|
||||
modalImg.style.maxHeight = `${maxHeight}px`;
|
||||
}
|
||||
}
|
||||
|
||||
// Инициализация после загрузки DOM
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Закрытие модального окна при клике вне изображения
|
||||
document.addEventListener('click', function(event) {
|
||||
const modal = document.getElementById('imageModal');
|
||||
if (event.target === modal) {
|
||||
closeModal();
|
||||
}
|
||||
});
|
||||
|
||||
// Закрытие по ESC
|
||||
document.addEventListener('keydown', function(event) {
|
||||
if (event.key === 'Escape') {
|
||||
closeModal();
|
||||
}
|
||||
});
|
||||
|
||||
// Адаптация размера изображения при изменении размера окна
|
||||
window.addEventListener('resize', function() {
|
||||
const modalImg = document.getElementById('modalImage');
|
||||
if (modalImg && modalImg.src) {
|
||||
adjustModalImageSize();
|
||||
}
|
||||
});
|
||||
|
||||
console.log('Recall page scripts initialized');
|
||||
});
|
||||
46
OneCprogsite/static/programmer/js/solution-accordion.js
Normal file
46
OneCprogsite/static/programmer/js/solution-accordion.js
Normal file
@ -0,0 +1,46 @@
|
||||
// solution-accordion.js
|
||||
function toggleAccordion(header) {
|
||||
const content = header.nextElementSibling;
|
||||
const icon = header.querySelector('.accordion-icon');
|
||||
|
||||
// Переключаем только текущий аккордеон
|
||||
header.classList.toggle('active');
|
||||
content.classList.toggle('active');
|
||||
icon.style.transform = header.classList.contains('active') ? 'rotate(180deg)' : 'rotate(0deg)';
|
||||
}
|
||||
|
||||
// Функция для открытия всех аккордеонов
|
||||
function expandAll() {
|
||||
document.querySelectorAll('.accordion-content').forEach(content => {
|
||||
content.classList.add('active');
|
||||
});
|
||||
document.querySelectorAll('.accordion-header').forEach(header => {
|
||||
header.classList.add('active');
|
||||
});
|
||||
document.querySelectorAll('.accordion-icon').forEach(icon => {
|
||||
icon.style.transform = 'rotate(180deg)';
|
||||
});
|
||||
}
|
||||
|
||||
// Функция для закрытия всех аккордеонов
|
||||
function collapseAll() {
|
||||
document.querySelectorAll('.accordion-content').forEach(content => {
|
||||
content.classList.remove('active');
|
||||
});
|
||||
document.querySelectorAll('.accordion-header').forEach(header => {
|
||||
header.classList.remove('active');
|
||||
});
|
||||
document.querySelectorAll('.accordion-icon').forEach(icon => {
|
||||
icon.style.transform = 'rotate(0deg)';
|
||||
});
|
||||
}
|
||||
|
||||
// Автоматически открываем первый аккордеон в каждой карточке при загрузке
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
document.querySelectorAll('.content-card').forEach(card => {
|
||||
const firstAccordion = card.querySelector('.accordion-header');
|
||||
if (firstAccordion) {
|
||||
toggleAccordion(firstAccordion);
|
||||
}
|
||||
});
|
||||
});
|
||||
68
OneCprogsite/static/programmer/js/theme-switcher.js
Normal file
68
OneCprogsite/static/programmer/js/theme-switcher.js
Normal file
@ -0,0 +1,68 @@
|
||||
// Theme Switcher Script
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const themeToggle = document.getElementById('theme-toggle');
|
||||
const mobileThemeToggle = document.getElementById('mobile-theme-toggle');
|
||||
const themeCSS = document.getElementById('theme-css');
|
||||
|
||||
// Проверяем сохраненную тему в localStorage
|
||||
const savedTheme = localStorage.getItem('theme');
|
||||
|
||||
// Устанавливаем светлую тему по умолчанию
|
||||
if (savedTheme === 'dark') {
|
||||
switchToDarkTheme();
|
||||
} else {
|
||||
switchToLightTheme(); // Светлая тема по умолчанию
|
||||
}
|
||||
|
||||
// Обработчик переключения темы для десктопного переключателя
|
||||
if (themeToggle) {
|
||||
themeToggle.addEventListener('change', function() {
|
||||
if (this.checked) {
|
||||
switchToLightTheme();
|
||||
} else {
|
||||
switchToDarkTheme();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Обработчик переключения темы для мобильного переключателя
|
||||
if (mobileThemeToggle) {
|
||||
mobileThemeToggle.addEventListener('change', function() {
|
||||
if (this.checked) {
|
||||
switchToLightTheme();
|
||||
} else {
|
||||
switchToDarkTheme();
|
||||
}
|
||||
// Синхронизируем оба переключателя
|
||||
if (themeToggle) {
|
||||
themeToggle.checked = this.checked;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function switchToLightTheme() {
|
||||
themeCSS.href = themeCSS.href.replace('styles_dark.css', 'styles_w.css');
|
||||
if (themeToggle) themeToggle.checked = true;
|
||||
if (mobileThemeToggle) mobileThemeToggle.checked = true;
|
||||
localStorage.setItem('theme', 'light');
|
||||
}
|
||||
|
||||
function switchToDarkTheme() {
|
||||
themeCSS.href = themeCSS.href.replace('styles_w.css', 'styles_dark.css');
|
||||
if (themeToggle) themeToggle.checked = false;
|
||||
if (mobileThemeToggle) mobileThemeToggle.checked = false;
|
||||
localStorage.setItem('theme', 'dark');
|
||||
}
|
||||
|
||||
// Синхронизация переключателей при загрузке
|
||||
if (themeToggle && mobileThemeToggle) {
|
||||
mobileThemeToggle.checked = themeToggle.checked;
|
||||
}
|
||||
|
||||
// Обработка ошибок загрузки CSS
|
||||
themeCSS.onerror = function() {
|
||||
console.error('Ошибка загрузки CSS файла темы');
|
||||
// Восстанавливаем светлую тему по умолчанию при ошибке
|
||||
themeCSS.href = themeCSS.href.replace('styles_dark.css', 'styles_w.css');
|
||||
};
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user