баннер с обратным отсчетом

remotes/origin/feature/school-only-may-24-04-19
gzbender 7 years ago
parent 97edbf221a
commit 0e1b71784c
  1. 12
      api/v1/serializers/content.py
  2. 4
      api/v1/urls.py
  3. 10
      api/v1/views.py
  4. 6
      apps/content/admin.py
  5. 23
      apps/content/migrations/0024_auto_20190418_2253.py
  6. 17
      apps/content/migrations/0025_auto_20190419_0103.py
  7. 18
      apps/content/migrations/0026_banner_stretch_image.py
  8. 10
      apps/content/models.py
  9. 6
      project/context_processors.py
  10. 2
      project/settings.py
  11. 16
      project/templates/blocks/baner.html
  12. 38
      project/templates/blocks/banner.html
  13. 2
      project/templates/lilcity/index.html
  14. 104
      web/src/components/blocks/Countdown.vue
  15. 11
      web/src/js/app.js
  16. 7
      web/src/js/modules/common.js
  17. 74
      web/src/sass/_common.sass

@ -3,7 +3,7 @@ from rest_framework import serializers
from django.conf import settings
from apps.content.models import (
Baner, Content, Image, Text, ImageText, Video,
Banner, Content, Image, Text, ImageText, Video,
Gallery, GalleryImage, ImageObject, FAQ)
from . import Base64ImageField
@ -24,11 +24,11 @@ BASE_CONTENT_FIELDS = (
)
class BanerSerializer(serializers.ModelSerializer):
class BannerSerializer(serializers.ModelSerializer):
image = serializers.SerializerMethodField()
class Meta:
model = Baner
model = Banner
fields = (
'id',
'text',
@ -46,9 +46,9 @@ class BanerSerializer(serializers.ModelSerializer):
'update_at',
)
def get_image(self, baner):
if baner.image:
return 'http://' + settings.MAIN_HOST + '/' + baner.image.url
def get_image(self, banner):
if banner.image:
return 'http://' + settings.MAIN_HOST + '/' + banner.image.url
else:
return None

@ -9,7 +9,7 @@ from drf_yasg import openapi
from .auth import ObtainToken, ObtainTempToken
from .views import (
AuthorBalanceViewSet, AuthorRequestViewSet,
BanerViewSet, ConfigViewSet, CategoryViewSet,
BannerViewSet, ConfigViewSet, CategoryViewSet,
CourseViewSet, CommentViewSet,
MaterialViewSet, LikeViewSet,
ImageViewSet, TextViewSet,
@ -24,7 +24,7 @@ from .views import (
router = DefaultRouter()
router.register(r'author-requests', AuthorRequestViewSet, base_name='author-requests')
router.register(r'author-balance', AuthorBalanceViewSet, base_name='author-balance')
router.register(r'baners', BanerViewSet, base_name='baners')
router.register(r'baners', BannerViewSet, base_name='banners')
router.register(r'categories', CategoryViewSet, base_name='categories')
router.register(r'courses', CourseViewSet, base_name='courses')
router.register(r'comments', CommentViewSet, base_name='comments')

@ -23,7 +23,7 @@ from .serializers.course import (
LikeCreateSerializer, CourseCommentSerializer, LessonCommentSerializer,
LiveLessonCommentSerializer,)
from .serializers.content import (
BanerSerializer,
BannerSerializer,
ImageSerializer, ImageCreateSerializer,
TextSerializer, TextCreateSerializer,
ImageTextSerializer, ImageTextCreateSerializer,
@ -63,7 +63,7 @@ from apps.course.models import (
LiveLessonComment)
from apps.config.models import Config
from apps.content.models import (
Baner, Image, Text, ImageText, Video,
Banner, Image, Text, ImageText, Video,
Gallery, GalleryImage, ImageObject,
Contest, ContestWork, FAQ)
from apps.payment.models import (
@ -132,9 +132,9 @@ class AuthorBalanceUsersViewSet(views.APIView):
return Response(UserSerializer(users, many=True).data)
class BanerViewSet(ExtendedModelViewSet):
queryset = Baner.objects.all()
serializer_class = BanerSerializer
class BannerViewSet(ExtendedModelViewSet):
queryset = Banner.objects.all()
serializer_class = BannerSerializer
permission_classes = (IsAdmin,)
filter_fields = ('use',)
ordering_fields = ('created_at', 'update_at',)

@ -6,14 +6,14 @@ from polymorphic.admin import (
)
from apps.content.models import (
Baner, Content, Image, Text, ImageText, Video,
Banner, Content, Image, Text, ImageText, Video,
Gallery, GalleryImage, ImageObject,
Contest, ContestWork, FAQ,
)
@admin.register(Baner)
class BanerAdmin(admin.ModelAdmin):
@admin.register(Banner)
class BannerAdmin(admin.ModelAdmin):
list_display = (
'text',
'button_text',

@ -0,0 +1,23 @@
# Generated by Django 2.0.7 on 2019-04-18 22:53
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('content', '0023_faq'),
]
operations = [
migrations.AddField(
model_name='baner',
name='color',
field=models.CharField(blank=True, default='', max_length=7),
),
migrations.AddField(
model_name='baner',
name='future_date',
field=models.DateTimeField(blank=True, null=True),
),
]

@ -0,0 +1,17 @@
# Generated by Django 2.0.7 on 2019-04-19 01:03
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('content', '0024_auto_20190418_2253'),
]
operations = [
migrations.RenameModel(
old_name='Baner',
new_name='Banner',
),
]

@ -0,0 +1,18 @@
# Generated by Django 2.0.7 on 2019-04-19 15:51
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('content', '0025_auto_20190419_0103'),
]
operations = [
migrations.AddField(
model_name='banner',
name='stretch_image',
field=models.BooleanField(default=True),
),
]

@ -132,13 +132,15 @@ class GalleryImage(models.Model):
ordering = ('-created_at',)
class Baner(models.Model):
class Banner(models.Model):
text = models.TextField()
button_text = models.CharField(max_length=50)
url = models.URLField()
image = models.ImageField()
use = models.BooleanField(default=False)
color = models.CharField(max_length=7, blank=True, default='')
stretch_image = models.BooleanField(default=True)
future_date = models.DateTimeField(blank=True, null=True)
created_at = models.DateTimeField(auto_now_add=True)
update_at = models.DateTimeField(auto_now=True)
@ -149,7 +151,7 @@ class Baner(models.Model):
def save(self, *args, **kwargs):
if self.use:
Baner.objects.filter(use=True).update(use=False)
Banner.objects.filter(use=True).update(use=False)
return super().save(*args, **kwargs)
@ -168,7 +170,7 @@ class Contest(models.Model):
date_start = models.DateField('Дата начала', null=True, blank=True)
date_end = models.DateField('Дата окончания', null=True, blank=True)
active = models.BooleanField(default=True)
# TODO? baner
# TODO? banner
@property
def finished(self):

@ -4,7 +4,7 @@ from paymentwall.pingback import Pingback
from django.contrib.auth import get_user_model
from django.conf import settings
from apps.config.models import Config
from apps.content.models import Baner
from apps.content.models import Banner
from apps.payment.models import SchoolPayment
User = get_user_model()
@ -14,8 +14,8 @@ def config(request):
return {"config": Config.load()}
def baner(request):
return {'baner': Baner.objects.filter(use=True).first()}
def banner(request):
return {'banner': Banner.objects.filter(use=True).first()}
def school_purchased(request):

@ -95,7 +95,7 @@ TEMPLATES = [
'OPTIONS': {
'context_processors': [
'project.context_processors.config',
'project.context_processors.baner',
'project.context_processors.banner',
'project.context_processors.school_purchased',
'project.context_processors.referrer',
'project.context_processors.settings',

@ -1,16 +0,0 @@
{% if baner %}
<div class="banner" data-banner="{{baner.id}}"
style="{% if not request.user_agent.is_mobile %}background-image: url({{ baner.image.url }});{% endif %} display: none;">
{% if request.user_agent.is_mobile %}
<a href="{{ baner.url }}" class="banner__image-wrap">
<img class="banner__image" src="{{ baner.image.url }}" />
</a>
{% else %}
<div class="banner__content">
<span class="banner__text">{{ baner.text }}</span>
<a href="{{ baner.url }}" class="banner__link">{{ baner.button_text }}</a>
</div>
{% endif %}
<a href="#" class="banner__hide">Скрыть баннер</a>
</div>
{% endif %}

@ -0,0 +1,38 @@
{% if banner %}
<div class="banner {% if banner.color %}banner_colored{% endif %} {% if banner.future_date %}banner_countdown{% endif %}"
data-banner="{{banner.id}}"
style="
{% if not request.user_agent.is_mobile %}
background-image: url({{ banner.image.url }});
{% endif %}
{% if banner.stretch_image %}
background-position: center;
background-size: cover;
{% else %}
background-position: center bottom;
{% endif %}
display: none;
background-color: {{ banner.color|default:'white' }};">
{# if request.user_agent.is_mobile #}
<!--<a href="{{ banner.url }}" class="banner__image-wrap">-->
<!--<img class="banner__image" src="{{ banner.image.url }}" />-->
<!--</a>-->
{# else #}
<div class="banner__content">
<div class="banner__content-center">
<div class="banner__text-column">
<div class="banner__text">{{ banner.text }}</div>
<a href="{{ banner.url }}" class="banner__link">{{ banner.button_text }}</a>
</div>
{% if banner.future_date %}
<div class="banner__countdown-column">
<div class="banner__countdown-title">До конца акции осталось</div>
<countdown date="{{ banner.future_date|date:'Y-m-d H:i:s' }}"></countdown>
</div>
{% endif %}
</div>
</div>
{# endif #}
<a href="#" class="banner__hide">Скрыть баннер</a>
</div>
{% endif %}

@ -32,7 +32,7 @@
{% block layer_body %}
{% include "templates/blocks/social.html" %}
{% include "templates/blocks/baner.html" %}
{% include "templates/blocks/banner.html" %}
<div class="outer js-outer">
{% include "templates/blocks/header.html" %}
<div id="lilcity-vue-app" class="container">

@ -0,0 +1,104 @@
<template>
<div class="banner__countdown" style="opacity: 0;">
<div>
<div class="banner__countdown-nums">
<div>{{ days[0] }}</div>
<div>{{ days[1] }}</div>
</div>
<div class="banner__countdown-descr">
Дней
</div>
</div>
<div class="banner__countdown-delim"></div>
<div>
<div class="banner__countdown-nums">
<div>{{ hours[0] }}</div>
<div>{{ hours[1] }}</div>
</div>
<div class="banner__countdown-descr">
Часов
</div>
</div>
<div class="banner__countdown-delim">:</div>
<div>
<div class="banner__countdown-nums">
<div>{{ minutes[0] }}</div>
<div>{{ minutes[1] }}</div>
</div>
<div class="banner__countdown-descr">
Минут
</div>
</div>
<div class="banner__countdown-delim">:</div>
<div>
<div class="banner__countdown-nums">
<div>{{ seconds[0] }}</div>
<div>{{ seconds[1] }}</div>
</div>
<div class="banner__countdown-descr">
Секунд
</div>
</div>
</div>
</template>
<script>
import moment from 'moment';
export default {
name: "Countdown",
props: ['date', 'format'],
data: () => ({
days: '00',
hours: '00',
minutes: '00',
seconds: '00',
i: 0,
}),
beforeDestroy(){
if ( window['cancelAnimationFrame'] ) {
window.cancelAnimationFrame(this.frame);
}
},
mounted() {
if ( window['requestAnimationFrame'] ) {
this.countdown = moment(this.date, this.format).toDate();
this.update();
}
},
methods: {
zerofill(value) {
return (value < 10 && value > -1 ? '0' : '') + value;
},
update() {
this.frame = window.requestAnimationFrame(this.update.bind(this));
if(this.i++ % 10 || this.$el.offsetParent === null) {
return;
}
this.$el.style.opacity = 1;
const t = this.countdown - (new Date());
if(t < 0){
this.days = this.hours = this.minutes = this.seconds = '00';
return;
}
this.days = this.zerofill(Math.floor(t / (1000 * 60 * 60 * 24)));
this.hours = this.zerofill(Math.floor((t / (1000 * 60 * 60)) % 24));
this.minutes = this.zerofill(Math.floor((t / 1000 / 60) % 60));
this.seconds = this.zerofill(Math.floor((t / 1000) % 60));
}
}
}
</script>
<style scoped>
</style>

@ -27,6 +27,7 @@ import DatePicker from 'vuejs-datepicker'
import Comments from '../components/Comments';
import Likes from '../components/blocks/Likes.vue';
import FAQ from '../components/FAQ.vue';
import Countdown from '../components/blocks/Countdown.vue';
Vue.use(Vuelidate);
Vue.use(VueAutosize);
@ -54,3 +55,13 @@ const app = new Vue({
},
components: components
});
const bannerApp = new Vue({
el: '.banner',
data() {
return {
store: window.LIL_STORE,
}
},
components: {'countdown': Countdown,}
});

@ -5,6 +5,7 @@ import SmoothScroll from 'smooth-scroll/dist/js/smooth-scroll';
import baguetteBox from 'baguettebox.js'
import createHistory from 'history/createBrowserHistory'
import Cookies from 'js-cookie'
import moment from 'moment'
window.$ = window.jQuery = jQuery = $;
window.Inputmask = Inputmask;
@ -32,6 +33,7 @@ $(document).ready(function () {
//===========BANNERS===============
const $banner = $('[data-banner]');
const bannerId = $banner.data('banner') + '';
const futureDate = $banner.data('future-date') + '';
if(Cookies.get('hide_banner') !== bannerId){
$banner.show();
}
@ -43,6 +45,11 @@ $(document).ready(function () {
Cookies.set('hide_banner', bannerId);
});
if(futureDate){
}
$banner.find('.banner__countdown')
//===========REVIEWS===============
if(window.LIL_STORE.isIndexPage){
const $reviews = $('.reviews');

@ -4388,10 +4388,7 @@ a
height: 140px
text-align: center
color: #fff
background-color: white
background-repeat: no-repeat
background-position: center
background-size: cover
+m
height: auto
&__image-wrap
@ -4405,15 +4402,33 @@ a
+m
width: 100%
display: block
margin: 0 auto
&_colored &__image
+m
max-width: 100%
width: auto
opactiy: 0.8
&__content
position: absolute
width: 100%
margin-top: 50px
+m
margin-top: -110px
&_countdown &__content
margin-top: 15px
&__content-center
width: 1024px
margin: 0 auto
display: flex
padding: 0 40px
&__text
font-size: 30px
text-shadow: 0px 0px 3px rgba(0, 0, 0, 1)
&_countdown &__text
font-size: 22px
text-shadow: none
color: black
width: 300px
&__link
display: block
color: #fff
@ -4422,6 +4437,20 @@ a
margin-top: 20px
+m
margin-top: 0px
&_countdown &__link
font-size: 15px
color: black
text-shadow: none
background: white
font-weight: bold
padding: 7px 20px
border-radius: 20px
border: 1px solid #ddd
text-align: center
margin-top: 10px
display: inline-block
&_countdown &__link:hover
background: #ddd
&__hide
position: absolute
right: 5px
@ -4434,6 +4463,45 @@ a
opacity: 0.3
+m
//margin-top: 0px
&__text-column
flex: 1
&_countdown &__text-column
text-align: left
&__countdown-column
padding: 0 20px
+m
border-radius: 3px
background: rgba(255, 255, 255, 0.3)
&__countdown-title
color: black
font-size: 15px
margin-bottom: 5px
&__countdown
display: flex
color: black
transition: 0.5s opacity
> div
font-size: 27px
display: flex
flex-direction: column
&-nums
display: flex
& > div
margin: 1px
width: 27px
border-radius: 5px
background: #000000ba
text-align: center
padding-top: 2px
color: white
&-delim
width: 10px
color: black
&-descr
text-align: center
font-size: 11px
margin-top: 3px
.anchor
padding-top: 100px

Loading…
Cancel
Save