├── .babelrc ├── api_v0 ├── __init__.py ├── admin.py ├── apps.py ├── migrations │ └── __init__.py ├── models.py ├── serializers.py ├── tests.py ├── urls.py └── views.py ├── articles ├── __init__.py ├── admin.py ├── apps.py ├── locale │ └── ru │ │ └── LC_MESSAGES │ │ ├── django.mo │ │ └── django.po ├── migrations │ ├── 0001_initial.py │ └── __init__.py ├── models.py ├── tests.py └── views.py ├── db.sqlite3 ├── djfront ├── __init__.py ├── settings.py ├── urls.py └── wsgi.py ├── main ├── __init__.py ├── admin.py ├── apps.py ├── migrations │ └── __init__.py ├── models.py ├── static │ └── app.js ├── templates │ └── main │ │ └── index.html ├── tests.py ├── urls.py └── views.py ├── manage.py ├── package.json ├── requirements.txt ├── web_client ├── _settings.scss ├── app.js ├── components │ ├── App │ │ └── index.jsx │ ├── Article │ │ ├── index.js │ │ └── style.sass │ ├── List │ │ ├── index.js │ │ └── style.sass │ ├── ListItem │ │ └── index.jsx │ └── index.js ├── layouts │ ├── BaseLayout │ │ ├── _app_mixins.sass │ │ ├── index.jsx │ │ └── style.sass │ └── index.js └── utils │ ├── format_date.js │ └── index.js └── webpack.config.babel.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015", 4 | "stage-0" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /api_v0/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/and-nothing-else/django-react-example/14a56860ad52e0c4378d59f9b58567b4f97f0e5e/api_v0/__init__.py -------------------------------------------------------------------------------- /api_v0/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /api_v0/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class ApiV0Config(AppConfig): 5 | name = 'api_v0' 6 | -------------------------------------------------------------------------------- /api_v0/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/and-nothing-else/django-react-example/14a56860ad52e0c4378d59f9b58567b4f97f0e5e/api_v0/migrations/__init__.py -------------------------------------------------------------------------------- /api_v0/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /api_v0/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | from articles.models import Article 3 | 4 | 5 | class ArticlePreviewSerializer(serializers.ModelSerializer): 6 | class Meta: 7 | model = Article 8 | fields = [ 9 | 'id', 10 | 'title', 11 | 'created_at', 12 | 'announce', 13 | 'url', 14 | ] 15 | 16 | 17 | class ArticleDetailSerializer(serializers.ModelSerializer): 18 | class Meta: 19 | model = Article 20 | fields = [ 21 | 'title', 22 | 'created_at', 23 | 'text', 24 | ] 25 | -------------------------------------------------------------------------------- /api_v0/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /api_v0/urls.py: -------------------------------------------------------------------------------- 1 | from rest_framework.routers import DefaultRouter 2 | from .views import * 3 | 4 | 5 | router = DefaultRouter() 6 | router.register(r'articles', ArticleViewSet) 7 | 8 | 9 | urlpatterns = router.urls 10 | -------------------------------------------------------------------------------- /api_v0/views.py: -------------------------------------------------------------------------------- 1 | from rest_framework import viewsets 2 | from .serializers import * 3 | 4 | 5 | class ArticleViewSet(viewsets.ReadOnlyModelViewSet): 6 | queryset = Article.objects.all() 7 | 8 | def get_serializer_class(self): 9 | if self.action == 'list': 10 | return ArticlePreviewSerializer 11 | return ArticleDetailSerializer 12 | -------------------------------------------------------------------------------- /articles/__init__.py: -------------------------------------------------------------------------------- 1 | default_app_config = 'articles.apps.ArticlesConfig' 2 | -------------------------------------------------------------------------------- /articles/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from .models import Article 3 | 4 | 5 | @admin.register(Article) 6 | class ArticleAdmin(admin.ModelAdmin): 7 | list_display = ['title', 'created_at'] 8 | -------------------------------------------------------------------------------- /articles/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | from django.utils.translation import ugettext_lazy as _ 3 | 4 | 5 | class ArticlesConfig(AppConfig): 6 | name = 'articles' 7 | verbose_name = _('Articles') 8 | -------------------------------------------------------------------------------- /articles/locale/ru/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/and-nothing-else/django-react-example/14a56860ad52e0c4378d59f9b58567b4f97f0e5e/articles/locale/ru/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /articles/locale/ru/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PACKAGE VERSION\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2016-05-01 13:51+0300\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "Language: \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" 20 | "%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n" 21 | "%100>=11 && n%100<=14)? 2 : 3);\n" 22 | 23 | #: apps.py:7 24 | msgid "Articles" 25 | msgstr "Статьи" 26 | 27 | #: models.py:6 28 | msgid "title" 29 | msgstr "заголовок" 30 | 31 | #: models.py:7 32 | msgid "created at" 33 | msgstr "время создания" 34 | 35 | #: models.py:8 36 | msgid "announce" 37 | msgstr "анонс" 38 | 39 | #: models.py:9 40 | msgid "text" 41 | msgstr "текст" 42 | 43 | #: models.py:20 44 | msgid "article" 45 | msgstr "статья" 46 | 47 | #: models.py:21 48 | msgid "articles" 49 | msgstr "статьи" 50 | -------------------------------------------------------------------------------- /articles/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.5 on 2016-05-01 10:49 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | initial = True 11 | 12 | dependencies = [ 13 | ] 14 | 15 | operations = [ 16 | migrations.CreateModel( 17 | name='Article', 18 | fields=[ 19 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 20 | ('title', models.CharField(max_length=128, verbose_name='title')), 21 | ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='created at')), 22 | ('announce_text', models.TextField(blank=True, max_length=512, verbose_name='announce')), 23 | ('text', models.TextField(max_length=4096, verbose_name='text')), 24 | ], 25 | options={ 26 | 'verbose_name': 'article', 27 | 'verbose_name_plural': 'articles', 28 | 'ordering': ['-created_at'], 29 | }, 30 | ), 31 | ] 32 | -------------------------------------------------------------------------------- /articles/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/and-nothing-else/django-react-example/14a56860ad52e0c4378d59f9b58567b4f97f0e5e/articles/migrations/__init__.py -------------------------------------------------------------------------------- /articles/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from django.utils.translation import ugettext_lazy as _ 3 | 4 | 5 | class Article(models.Model): 6 | title = models.CharField(_('title'), max_length=128) 7 | created_at = models.DateTimeField(_('created at'), auto_now_add=True) 8 | announce_text = models.TextField(_('announce'), max_length=512, blank=True) 9 | text = models.TextField(_('text'), max_length=4096) 10 | 11 | def __str__(self): 12 | return self.title 13 | 14 | @property 15 | def announce(self): 16 | return self.announce_text or self.text[:512].rsplit(' ', 1)[0] 17 | 18 | class Meta: 19 | ordering = ['-created_at'] 20 | verbose_name = _('article') 21 | verbose_name_plural = _('articles') 22 | -------------------------------------------------------------------------------- /articles/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /articles/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | # Create your views here. 4 | -------------------------------------------------------------------------------- /db.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/and-nothing-else/django-react-example/14a56860ad52e0c4378d59f9b58567b4f97f0e5e/db.sqlite3 -------------------------------------------------------------------------------- /djfront/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/and-nothing-else/django-react-example/14a56860ad52e0c4378d59f9b58567b4f97f0e5e/djfront/__init__.py -------------------------------------------------------------------------------- /djfront/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for djfront project. 3 | 4 | Generated by 'django-admin startproject' using Django 1.9.5. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.9/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/1.9/ref/settings/ 11 | """ 12 | 13 | import os 14 | 15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 17 | 18 | 19 | # Quick-start development settings - unsuitable for production 20 | # See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/ 21 | 22 | # SECURITY WARNING: keep the secret key used in production secret! 23 | SECRET_KEY = 'q87gozw=o-6+a@jib@&(y8__r=k)bau^&58%0@y@k12h=+s=-(' 24 | 25 | # SECURITY WARNING: don't run with debug turned on in production! 26 | DEBUG = True 27 | 28 | ALLOWED_HOSTS = [] 29 | 30 | 31 | # Application definition 32 | 33 | INSTALLED_APPS = [ 34 | 'django.contrib.admin', 35 | 'django.contrib.auth', 36 | 'django.contrib.contenttypes', 37 | 'django.contrib.sessions', 38 | 'django.contrib.messages', 39 | 'django.contrib.staticfiles', 40 | 'rest_framework', 41 | 'api_v0', 42 | 'main', 43 | 'articles', 44 | ] 45 | 46 | MIDDLEWARE_CLASSES = [ 47 | 'django.middleware.security.SecurityMiddleware', 48 | 'django.contrib.sessions.middleware.SessionMiddleware', 49 | 'django.middleware.common.CommonMiddleware', 50 | 'django.middleware.csrf.CsrfViewMiddleware', 51 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 52 | 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 53 | 'django.contrib.messages.middleware.MessageMiddleware', 54 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 55 | ] 56 | 57 | ROOT_URLCONF = 'djfront.urls' 58 | 59 | TEMPLATES = [ 60 | { 61 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 62 | 'DIRS': [], 63 | 'APP_DIRS': True, 64 | 'OPTIONS': { 65 | 'context_processors': [ 66 | 'django.template.context_processors.debug', 67 | 'django.template.context_processors.request', 68 | 'django.contrib.auth.context_processors.auth', 69 | 'django.contrib.messages.context_processors.messages', 70 | ], 71 | }, 72 | }, 73 | ] 74 | 75 | WSGI_APPLICATION = 'djfront.wsgi.application' 76 | 77 | 78 | # Database 79 | # https://docs.djangoproject.com/en/1.9/ref/settings/#databases 80 | 81 | DATABASES = { 82 | 'default': { 83 | 'ENGINE': 'django.db.backends.sqlite3', 84 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 85 | } 86 | } 87 | 88 | 89 | # Password validation 90 | # https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators 91 | 92 | AUTH_PASSWORD_VALIDATORS = [ 93 | { 94 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 95 | }, 96 | { 97 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 98 | }, 99 | { 100 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 101 | }, 102 | { 103 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 104 | }, 105 | ] 106 | 107 | 108 | # Internationalization 109 | # https://docs.djangoproject.com/en/1.9/topics/i18n/ 110 | 111 | LANGUAGE_CODE = 'ru' 112 | 113 | TIME_ZONE = 'Europe/Moscow' 114 | 115 | USE_I18N = True 116 | 117 | USE_L10N = True 118 | 119 | USE_TZ = True 120 | 121 | 122 | # Static files (CSS, JavaScript, Images) 123 | # https://docs.djangoproject.com/en/1.9/howto/static-files/ 124 | 125 | STATIC_URL = '/static/' 126 | MEDIA_URL = '/media/' 127 | MEDIA_ROOT = os.path.join(BASE_DIR, 'media') 128 | STATIC_ROOT = os.path.join(BASE_DIR, 'static') 129 | STATICFILES_DIRS = () 130 | -------------------------------------------------------------------------------- /djfront/urls.py: -------------------------------------------------------------------------------- 1 | """djfront URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/1.9/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.conf.urls import url, include 14 | 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) 15 | """ 16 | from django.conf.urls import url, include 17 | from django.contrib import admin 18 | 19 | urlpatterns = [ 20 | url(r'^admin/', admin.site.urls), 21 | url(r'^api/v0/', include('api_v0.urls')), 22 | url(r'^', include('main.urls')), 23 | ] 24 | -------------------------------------------------------------------------------- /djfront/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for djfront project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.9/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "djfront.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /main/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/and-nothing-else/django-react-example/14a56860ad52e0c4378d59f9b58567b4f97f0e5e/main/__init__.py -------------------------------------------------------------------------------- /main/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /main/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class MainConfig(AppConfig): 5 | name = 'main' 6 | -------------------------------------------------------------------------------- /main/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/and-nothing-else/django-react-example/14a56860ad52e0c4378d59f9b58567b4f97f0e5e/main/migrations/__init__.py -------------------------------------------------------------------------------- /main/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /main/templates/main/index.html: -------------------------------------------------------------------------------- 1 | {% load staticfiles %} 2 | Демо проект 3 |
4 | 5 | -------------------------------------------------------------------------------- /main/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /main/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | from .views import * 3 | 4 | 5 | urlpatterns = [ 6 | url(r'^', IndexView.as_view()), 7 | ] 8 | -------------------------------------------------------------------------------- /main/views.py: -------------------------------------------------------------------------------- 1 | from django.views.generic import TemplateView 2 | 3 | 4 | class IndexView(TemplateView): 5 | template_name = 'main/index.html' 6 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "djfront.settings") 7 | 8 | from django.core.management import execute_from_command_line 9 | 10 | execute_from_command_line(sys.argv) 11 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "djfront", 3 | "version": "1.0.0", 4 | "description": "Demo project", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "./node_modules/.bin/webpack --progress --watch", 8 | "build": "./node_modules/.bin/webpack --progress --production --optimize-minimize" 9 | }, 10 | "author": "And Nothing Else", 11 | "license": "MIT", 12 | "devDependencies": { 13 | "autoprefixer": "^6.3.6", 14 | "babel-core": "^6.7.7", 15 | "babel-loader": "^6.2.4", 16 | "babel-plugin-transform-runtime": "^6.7.5", 17 | "babel-preset-es2015": "^6.6.0", 18 | "babel-preset-react": "^6.5.0", 19 | "babel-preset-stage-0": "^6.5.0", 20 | "bootstrap": "^4.0.0-alpha.2", 21 | "css-loader": "^0.23.1", 22 | "moment": "^2.13.0", 23 | "node-sass": "^3.6.0", 24 | "postcss-loader": "^0.9.1", 25 | "react": "^15.0.2", 26 | "react-addons-css-transition-group": "^15.0.2", 27 | "react-dom": "^15.0.2", 28 | "react-router": "^2.4.0", 29 | "sass-loader": "^3.2.0", 30 | "style-loader": "^0.13.1", 31 | "webpack": "^1.13.0" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | django==1.9.5 2 | djangorestframework==3.3.3 3 | -------------------------------------------------------------------------------- /web_client/_settings.scss: -------------------------------------------------------------------------------- 1 | // Variables 2 | // 3 | // Copy settings from this file into the provided `_custom.scss` to override 4 | // the Bootstrap defaults without modifying key, versioned files. 5 | 6 | 7 | // Table of Contents 8 | // 9 | // Colors 10 | // Options 11 | // Spacing 12 | // Body 13 | // Links 14 | // Grid breakpoints 15 | // Grid containers 16 | // Grid columns 17 | // Fonts 18 | // Components 19 | 20 | // General variable structure 21 | // 22 | // Variable format should follow the `$component-modifier-state-property` order. 23 | 24 | 25 | // Colors 26 | // 27 | // Grayscale and brand colors for use across Bootstrap. 28 | 29 | $gray-dark: #373a3c !default; 30 | $gray: #55595c !default; 31 | $gray-light: #818a91 !default; 32 | $gray-lighter: #eceeef !default; 33 | $gray-lightest: #f7f7f9 !default; 34 | 35 | $brand-primary: #7d0000 !default; 36 | $brand-success: #5cb85c !default; 37 | $brand-info: #5bc0de !default; 38 | $brand-warning: #f0ad4e !default; 39 | $brand-danger: #d9534f !default; 40 | 41 | 42 | // Options 43 | // 44 | // Quickly modify global styling by enabling or disabling optional features. 45 | 46 | $enable-flex: true !default; 47 | $enable-rounded: true !default; 48 | $enable-shadows: false !default; 49 | $enable-gradients: false !default; 50 | $enable-transitions: true !default; 51 | $enable-hover-media-query: false !default; 52 | $enable-grid-classes: false !default; 53 | 54 | 55 | $transition-duration: .5s; 56 | $hover-transition-duration: .3s; 57 | 58 | // Spacing 59 | // 60 | // Control the default styling of most Bootstrap elements by modifying these 61 | // variables. Mostly focused on spacing. 62 | 63 | $spacer: 1rem !default; 64 | $spacer-x: $spacer !default; 65 | $spacer-y: $spacer !default; 66 | $spacers: ( 67 | 0: ( 68 | x: 0, 69 | y: 0 70 | ), 71 | 1: ( 72 | x: $spacer-x, 73 | y: $spacer-y 74 | ), 75 | 2: ( 76 | x: ($spacer-x * 1.5), 77 | y: ($spacer-y * 1.5) 78 | ), 79 | 3: ( 80 | x: ($spacer-x * 3), 81 | y: ($spacer-y * 3) 82 | ) 83 | ) !default; 84 | $border-width: 1px !default; 85 | 86 | 87 | $header-height: 60px; 88 | 89 | // Body 90 | // 91 | // Settings for the `` element. 92 | 93 | $body-bg: #eee !default; 94 | $body-color: $gray-dark !default; 95 | 96 | 97 | // Links 98 | // 99 | // Style anchor elements. 100 | 101 | $link-color: $brand-primary !default; 102 | $link-decoration: none !default; 103 | $link-hover-color: darken($link-color, 15%) !default; 104 | $link-hover-decoration: underline !default; 105 | 106 | 107 | // Grid breakpoints 108 | // 109 | // Define the minimum and maximum dimensions at which your layout will change, 110 | // adapting to different screen sizes, for use in media queries. 111 | 112 | $grid-breakpoints: ( 113 | // Extra small screen / phone 114 | xs: 0, 115 | // Small screen / phone 116 | sm: 544px, 117 | // Medium screen / tablet 118 | md: 768px, 119 | // Large screen / desktop 120 | lg: 992px, 121 | // Extra large screen / wide desktop 122 | xl: 1200px 123 | ) !default; 124 | 125 | 126 | // Grid containers 127 | // 128 | // Define the maximum width of `.container` for different screen sizes. 129 | 130 | $container-max-widths: ( 131 | sm: 576px, 132 | md: 720px, 133 | lg: 940px, 134 | xl: 1140px 135 | ) !default; 136 | 137 | 138 | // Grid columns 139 | // 140 | // Set the number of columns and specify the width of the gutters. 141 | 142 | $grid-columns: 12 !default; 143 | $grid-gutter-width: 1.875rem !default; // 30px 144 | 145 | 146 | // Typography 147 | // 148 | // Font, line-height, and color for body text, headings, and more. 149 | 150 | $font-family-sans-serif: "Helvetica Neue", Helvetica, Arial, sans-serif !default; 151 | $font-family-serif: Georgia, "Times New Roman", Times, serif !default; 152 | $font-family-monospace: Menlo, Monaco, Consolas, "Courier New", monospace !default; 153 | $font-family-base: $font-family-sans-serif !default; 154 | 155 | // Pixel value used to responsively scale all typography. Applied to the `` element. 156 | $font-size-root: 16px !default; 157 | 158 | $font-size-base: 1rem !default; 159 | $font-size-lg: 1.25rem !default; 160 | $font-size-sm: .875rem !default; 161 | $font-size-xs: .75rem !default; 162 | 163 | $font-size-h1: 2.5rem !default; 164 | $font-size-h2: 2rem !default; 165 | $font-size-h3: 1.75rem !default; 166 | $font-size-h4: 1.5rem !default; 167 | $font-size-h5: 1.25rem !default; 168 | $font-size-h6: 1rem !default; 169 | 170 | $display1-size: 6rem !default; 171 | $display2-size: 5.5rem !default; 172 | $display3-size: 4.5rem !default; 173 | $display4-size: 3.5rem !default; 174 | 175 | $display1-weight: 300 !default; 176 | $display2-weight: 300 !default; 177 | $display3-weight: 300 !default; 178 | $display4-weight: 300 !default; 179 | 180 | $line-height: 1.5 !default; 181 | 182 | $headings-margin-bottom: ($spacer / 2) !default; 183 | $headings-font-family: inherit !default; 184 | $headings-font-weight: 500 !default; 185 | $headings-line-height: 1.1 !default; 186 | $headings-color: inherit !default; 187 | 188 | $lead-font-size: 1.25rem !default; 189 | $lead-font-weight: 300 !default; 190 | 191 | $text-muted: $gray-light !default; 192 | 193 | $abbr-border-color: $gray-light !default; 194 | 195 | $blockquote-small-color: $gray-light !default; 196 | $blockquote-font-size: ($font-size-base * 1.25) !default; 197 | $blockquote-border-color: $gray-lighter !default; 198 | 199 | $hr-border-color: rgba(0,0,0,.1) !default; 200 | $hr-border-width: $border-width !default; 201 | 202 | $dt-font-weight: bold !default; 203 | 204 | $nested-kbd-font-weight: bold !default; 205 | 206 | $list-inline-padding: 5px !default; 207 | 208 | 209 | // Components 210 | // 211 | // Define common padding and border radius sizes and more. 212 | 213 | $line-height-lg: (4 / 3) !default; 214 | $line-height-sm: 1.5 !default; 215 | 216 | $border-radius: .25rem !default; 217 | $border-radius-lg: .3rem !default; 218 | $border-radius-sm: .2rem !default; 219 | 220 | $component-active-color: #fff !default; 221 | $component-active-bg: $brand-primary !default; 222 | 223 | $caret-width: .3em !default; 224 | $caret-width-lg: $caret-width !default; 225 | 226 | 227 | // Tables 228 | // 229 | // Customizes the `.table` component with basic values, each used across all table variations. 230 | 231 | $table-cell-padding: .75rem !default; 232 | $table-sm-cell-padding: .3rem !default; 233 | 234 | $table-bg: transparent !default; 235 | $table-bg-accent: #f9f9f9 !default; 236 | $table-bg-hover: #f5f5f5 !default; 237 | $table-bg-active: $table-bg-hover !default; 238 | 239 | $table-border-width: $border-width !default; 240 | $table-border-color: $gray-lighter !default; 241 | 242 | 243 | // Buttons 244 | // 245 | // For each of Bootstrap's buttons, define text, background and border color. 246 | 247 | $btn-padding-x: 1rem !default; 248 | $btn-padding-y: .375rem !default; 249 | $btn-font-weight: normal !default; 250 | 251 | $btn-primary-color: #fff !default; 252 | $btn-primary-bg: $brand-primary !default; 253 | $btn-primary-border: $btn-primary-bg !default; 254 | 255 | $btn-secondary-color: $gray-dark !default; 256 | $btn-secondary-bg: #fff !default; 257 | $btn-secondary-border: #ccc !default; 258 | 259 | $btn-info-color: #fff !default; 260 | $btn-info-bg: $brand-info !default; 261 | $btn-info-border: $btn-info-bg !default; 262 | 263 | $btn-success-color: #fff !default; 264 | $btn-success-bg: $brand-success !default; 265 | $btn-success-border: $btn-success-bg !default; 266 | 267 | $btn-warning-color: #fff !default; 268 | $btn-warning-bg: $brand-warning !default; 269 | $btn-warning-border: $btn-warning-bg !default; 270 | 271 | $btn-danger-color: #fff !default; 272 | $btn-danger-bg: $brand-danger !default; 273 | $btn-danger-border: $btn-danger-bg !default; 274 | 275 | $btn-link-disabled-color: $gray-light !default; 276 | 277 | $btn-padding-x-sm: .75rem !default; 278 | $btn-padding-y-sm: .25rem !default; 279 | 280 | $btn-padding-x-lg: 1.25rem !default; 281 | $btn-padding-y-lg: .75rem !default; 282 | 283 | // Allows for customizing button radius independently from global border radius 284 | $btn-border-radius: $border-radius !default; 285 | $btn-border-radius-lg: $border-radius-lg !default; 286 | $btn-border-radius-sm: $border-radius-sm !default; 287 | 288 | 289 | // Forms 290 | 291 | $input-padding-x: .75rem !default; 292 | $input-padding-y: .375rem !default; 293 | 294 | $input-bg: #fff !default; 295 | $input-bg-disabled: $gray-lighter !default; 296 | 297 | $input-color: $gray !default; 298 | $input-border-color: #ccc !default; 299 | $input-btn-border-width: $border-width !default; // For form controls and buttons 300 | $input-box-shadow: inset 0 1px 1px rgba(0,0,0,.075) !default; 301 | 302 | $input-border-radius: $border-radius !default; 303 | $input-border-radius-lg: $border-radius-lg !default; 304 | $input-border-radius-sm: $border-radius-sm !default; 305 | 306 | $input-border-focus: #66afe9 !default; 307 | $input-box-shadow-focus: rgba(102,175,233,.6) !default; 308 | 309 | $input-color-placeholder: #999 !default; 310 | 311 | $input-padding-x-sm: .75rem !default; 312 | $input-padding-y-sm: .275rem !default; 313 | 314 | $input-padding-x-lg: 1.25rem !default; 315 | $input-padding-y-lg: .75rem !default; 316 | 317 | $input-height: (($font-size-base * $line-height) + ($input-padding-y * 2)) !default; 318 | $input-height-lg: (($font-size-lg * $line-height-lg) + ($input-padding-y-lg * 2)) !default; 319 | $input-height-sm: (($font-size-sm * $line-height-sm) + ($input-padding-y-sm * 2)) !default; 320 | 321 | $form-group-margin-bottom: $spacer-y !default; 322 | 323 | $input-group-addon-bg: $gray-lighter !default; 324 | $input-group-addon-border-color: $input-border-color !default; 325 | 326 | $cursor-disabled: not-allowed !default; 327 | 328 | // Form validation icons 329 | $form-icon-success: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2MTIgNzkyIj48cGF0aCBmaWxsPSIjNWNiODVjIiBkPSJNMjMzLjggNjEwYy0xMy4zIDAtMjYtNi0zNC0xNi44TDkwLjUgNDQ4LjhDNzYuMyA0MzAgODAgNDAzLjMgOTguOCAzODljMTguOC0xNC4yIDQ1LjUtMTAuNCA1OS44IDguNGw3MiA5NUw0NTEuMyAyNDJjMTIuNS0yMCAzOC44LTI2LjIgNTguOC0xMy43IDIwIDEyLjQgMjYgMzguNyAxMy43IDU4LjhMMjcwIDU5MGMtNy40IDEyLTIwLjIgMTkuNC0zNC4zIDIwaC0yeiIvPjwvc3ZnPg==" !default; 330 | $form-icon-warning: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2MTIgNzkyIj48cGF0aCBmaWxsPSIjZjBhZDRlIiBkPSJNNjAzIDY0MC4ybC0yNzguNS01MDljLTMuOC02LjYtMTAuOC0xMC42LTE4LjUtMTAuNnMtMTQuNyA0LTE4LjUgMTAuNkw5IDY0MC4yYy0zLjcgNi41LTMuNiAxNC40LjIgMjAuOCAzLjggNi41IDEwLjggMTAuNCAxOC4zIDEwLjRoNTU3YzcuNiAwIDE0LjYtNCAxOC40LTEwLjQgMy41LTYuNCAzLjYtMTQuNCAwLTIwLjh6bS0yNjYuNC0zMGgtNjEuMlY1NDloNjEuMnY2MS4yem0wLTEwN2gtNjEuMlYzMDRoNjEuMnYxOTl6Ii8+PC9zdmc+" !default; 331 | $form-icon-danger: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2MTIgNzkyIj48cGF0aCBmaWxsPSIjZDk1MzRmIiBkPSJNNDQ3IDU0NC40Yy0xNC40IDE0LjQtMzcuNiAxNC40LTUyIDBsLTg5LTkyLjctODkgOTIuN2MtMTQuNSAxNC40LTM3LjcgMTQuNC01MiAwLTE0LjQtMTQuNC0xNC40LTM3LjYgMC01Mmw5Mi40LTk2LjMtOTIuNC05Ni4zYy0xNC40LTE0LjQtMTQuNC0zNy42IDAtNTJzMzcuNi0xNC4zIDUyIDBsODkgOTIuOCA4OS4yLTkyLjdjMTQuNC0xNC40IDM3LjYtMTQuNCA1MiAwIDE0LjMgMTQuNCAxNC4zIDM3LjYgMCA1MkwzNTQuNiAzOTZsOTIuNCA5Ni40YzE0LjQgMTQuNCAxNC40IDM3LjYgMCA1MnoiLz48L3N2Zz4=" !default; 332 | 333 | 334 | // Dropdowns 335 | // 336 | // Dropdown menu container and contents. 337 | 338 | $dropdown-bg: #fff !default; 339 | $dropdown-border-color: rgba(0,0,0,.15) !default; 340 | $dropdown-border-width: $border-width !default; 341 | $dropdown-divider-bg: #e5e5e5 !default; 342 | 343 | $dropdown-link-color: $gray-dark !default; 344 | $dropdown-link-hover-color: darken($gray-dark, 5%) !default; 345 | $dropdown-link-hover-bg: #f5f5f5 !default; 346 | 347 | $dropdown-link-active-color: $component-active-color !default; 348 | $dropdown-link-active-bg: $component-active-bg !default; 349 | 350 | $dropdown-link-disabled-color: $gray-light !default; 351 | 352 | $dropdown-header-color: $gray-light !default; 353 | 354 | 355 | // Z-index master list 356 | // 357 | // Warning: Avoid customizing these values. They're used for a bird's eye view 358 | // of components dependent on the z-axis and are designed to all work together. 359 | 360 | $zindex-navbar: 1000 !default; 361 | $zindex-dropdown: 1000 !default; 362 | $zindex-popover: 1060 !default; 363 | $zindex-tooltip: 1070 !default; 364 | $zindex-navbar-fixed: 1030 !default; 365 | $zindex-navbar-sticky: 1030 !default; 366 | $zindex-modal-bg: 1040 !default; 367 | $zindex-modal: 1050 !default; 368 | 369 | 370 | // Navbar 371 | 372 | $navbar-border-radius: $border-radius !default; 373 | $navbar-padding-horizontal: $spacer !default; 374 | $navbar-padding-vertical: ($spacer / 2) !default; 375 | 376 | $navbar-dark-color: rgba(255,255,255,.5) !default; 377 | $navbar-dark-hover-color: rgba(255,255,255,.75) !default; 378 | $navbar-dark-active-color: rgba(255,255,255,1) !default; 379 | $navbar-dark-disabled-color: rgba(255,255,255,.25) !default; 380 | 381 | $navbar-light-color: rgba(0,0,0,.3) !default; 382 | $navbar-light-hover-color: rgba(0,0,0,.6) !default; 383 | $navbar-light-active-color: rgba(0,0,0,.8) !default; 384 | $navbar-light-disabled-color: rgba(0,0,0,.15) !default; 385 | 386 | 387 | // Navs 388 | 389 | $nav-link-padding: .5em 1em !default; 390 | $nav-link-hover-bg: $gray-lighter !default; 391 | 392 | $nav-disabled-link-color: $gray-light !default; 393 | $nav-disabled-link-hover-color: $gray-light !default; 394 | 395 | $nav-tabs-border-color: #ddd !default; 396 | 397 | $nav-tabs-link-border-width: $border-width !default; 398 | $nav-tabs-link-hover-border-color: $gray-lighter !default; 399 | 400 | $nav-tabs-active-link-hover-bg: $body-bg !default; 401 | $nav-tabs-active-link-hover-color: $gray !default; 402 | $nav-tabs-active-link-hover-border-color: #ddd !default; 403 | 404 | $nav-tabs-justified-link-border-color: #ddd !default; 405 | $nav-tabs-justified-active-link-border-color: $body-bg !default; 406 | 407 | $nav-pills-border-radius: $border-radius !default; 408 | $nav-pills-active-link-hover-bg: $component-active-bg !default; 409 | $nav-pills-active-link-hover-color: $component-active-color !default; 410 | 411 | 412 | // Pagination 413 | 414 | $pagination-padding-x: .75rem !default; 415 | $pagination-padding-y: .5rem !default; 416 | $pagination-padding-x-sm: .75rem !default; 417 | $pagination-padding-y-sm: .275rem !default; 418 | $pagination-padding-x-lg: 1.5rem !default; 419 | $pagination-padding-y-lg: .75rem !default; 420 | 421 | 422 | $pagination-color: $link-color !default; 423 | $pagination-bg: #fff !default; 424 | $pagination-border-width: $border-width !default; 425 | $pagination-border-color: #ddd !default; 426 | 427 | $pagination-hover-color: $link-hover-color !default; 428 | $pagination-hover-bg: $gray-lighter !default; 429 | $pagination-hover-border: #ddd !default; 430 | 431 | $pagination-active-color: #fff !default; 432 | $pagination-active-bg: $brand-primary !default; 433 | $pagination-active-border: $brand-primary !default; 434 | 435 | $pagination-disabled-color: $gray-light !default; 436 | $pagination-disabled-bg: #fff !default; 437 | $pagination-disabled-border: #ddd !default; 438 | 439 | 440 | // Pager 441 | 442 | $pager-bg: $pagination-bg !default; 443 | $pager-border-width: $border-width !default; 444 | $pager-border-color: $pagination-border-color !default; 445 | $pager-border-radius: 15px !default; 446 | 447 | $pager-hover-bg: $pagination-hover-bg !default; 448 | 449 | $pager-active-bg: $pagination-active-bg !default; 450 | $pager-active-color: $pagination-active-color !default; 451 | 452 | $pager-disabled-color: $pagination-disabled-color !default; 453 | 454 | 455 | // Jumbotron 456 | 457 | $jumbotron-padding: 2rem !default; 458 | $jumbotron-bg: $gray-lighter !default; 459 | 460 | 461 | // Form states and alerts 462 | // 463 | // Define colors for form feedback states and, by default, alerts. 464 | 465 | $state-success-text: #3c763d !default; 466 | $state-success-bg: #dff0d8 !default; 467 | $state-success-border: darken($state-success-bg, 5%) !default; 468 | 469 | $state-info-text: #31708f !default; 470 | $state-info-bg: #d9edf7 !default; 471 | $state-info-border: darken($state-info-bg, 7%) !default; 472 | 473 | $state-warning-text: #8a6d3b !default; 474 | $state-warning-bg: #fcf8e3 !default; 475 | $state-warning-border: darken($state-warning-bg, 5%) !default; 476 | 477 | $state-danger-text: #a94442 !default; 478 | $state-danger-bg: #f2dede !default; 479 | $state-danger-border: darken($state-danger-bg, 5%) !default; 480 | 481 | 482 | // Cards 483 | $card-spacer-x: 1.25rem !default; 484 | $card-spacer-y: .75rem !default; 485 | $card-border-width: 1px !default; 486 | $card-border-radius: $border-radius !default; 487 | $card-border-color: #e5e5e5 !default; 488 | $card-border-radius-inner: $card-border-radius !default; 489 | $card-cap-bg: #f5f5f5 !default; 490 | $card-bg: #fff !default; 491 | 492 | $card-link-hover-color: #fff !default; 493 | 494 | 495 | // Tooltips 496 | 497 | $tooltip-max-width: 200px !default; 498 | $tooltip-color: #fff !default; 499 | $tooltip-bg: #000 !default; 500 | $tooltip-opacity: .9 !default; 501 | 502 | $tooltip-arrow-width: 5px !default; 503 | $tooltip-arrow-color: $tooltip-bg !default; 504 | 505 | 506 | // Popovers 507 | 508 | $popover-bg: #fff !default; 509 | $popover-max-width: 276px !default; 510 | $popover-border-width: $border-width !default; 511 | $popover-border-color: rgba(0,0,0,.2) !default; 512 | 513 | $popover-title-bg: darken($popover-bg, 3%) !default; 514 | 515 | $popover-arrow-width: 10px !default; 516 | $popover-arrow-color: $popover-bg !default; 517 | 518 | $popover-arrow-outer-width: ($popover-arrow-width + 1) !default; 519 | $popover-arrow-outer-color: fade-in($popover-border-color, 0.05) !default; 520 | 521 | 522 | // Labels 523 | 524 | $label-default-bg: $gray-light !default; 525 | $label-primary-bg: $brand-primary !default; 526 | $label-success-bg: $brand-success !default; 527 | $label-info-bg: $brand-info !default; 528 | $label-warning-bg: $brand-warning !default; 529 | $label-danger-bg: $brand-danger !default; 530 | 531 | $label-color: #fff !default; 532 | $label-link-hover-color: #fff !default; 533 | $label-font-weight: bold !default; 534 | 535 | 536 | // Modals 537 | 538 | // Padding applied to the modal body 539 | $modal-inner-padding: 15px !default; 540 | 541 | $modal-title-padding: 15px !default; 542 | $modal-title-line-height: $line-height !default; 543 | 544 | $modal-content-bg: #fff !default; 545 | $modal-content-border-color: rgba(0,0,0,.2) !default; 546 | 547 | $modal-backdrop-bg: #000 !default; 548 | $modal-backdrop-opacity: .5 !default; 549 | $modal-header-border-color: #e5e5e5 !default; 550 | $modal-footer-border-color: $modal-header-border-color !default; 551 | 552 | $modal-lg: 900px !default; 553 | $modal-md: 600px !default; 554 | $modal-sm: 300px !default; 555 | 556 | 557 | // Alerts 558 | // 559 | // Define alert colors, border radius, and padding. 560 | 561 | $alert-padding: 15px !default; 562 | $alert-border-radius: $border-radius !default; 563 | $alert-link-font-weight: bold !default; 564 | $alert-border-width: $border-width !default; 565 | 566 | $alert-success-bg: $state-success-bg !default; 567 | $alert-success-text: $state-success-text !default; 568 | $alert-success-border: $state-success-border !default; 569 | 570 | $alert-info-bg: $state-info-bg !default; 571 | $alert-info-text: $state-info-text !default; 572 | $alert-info-border: $state-info-border !default; 573 | 574 | $alert-warning-bg: $state-warning-bg !default; 575 | $alert-warning-text: $state-warning-text !default; 576 | $alert-warning-border: $state-warning-border !default; 577 | 578 | $alert-danger-bg: $state-danger-bg !default; 579 | $alert-danger-text: $state-danger-text !default; 580 | $alert-danger-border: $state-danger-border !default; 581 | 582 | 583 | // Progress bars 584 | 585 | $progress-bg: #f5f5f5 !default; 586 | $progress-bar-color: #fff !default; 587 | $progress-border-radius: $border-radius !default; 588 | 589 | $progress-bar-bg: $brand-primary !default; 590 | $progress-bar-success-bg: $brand-success !default; 591 | $progress-bar-warning-bg: $brand-warning !default; 592 | $progress-bar-danger-bg: $brand-danger !default; 593 | $progress-bar-info-bg: $brand-info !default; 594 | 595 | 596 | // List group 597 | 598 | $list-group-bg: #fff !default; 599 | $list-group-border-color: #ddd !default; 600 | $list-group-border-width: $border-width !default; 601 | $list-group-border-radius: $border-radius !default; 602 | 603 | $list-group-hover-bg: #f5f5f5 !default; 604 | $list-group-active-color: $component-active-color !default; 605 | $list-group-active-bg: $component-active-bg !default; 606 | $list-group-active-border: $list-group-active-bg !default; 607 | $list-group-active-text-color: lighten($list-group-active-bg, 40%) !default; 608 | 609 | $list-group-disabled-color: $gray-light !default; 610 | $list-group-disabled-bg: $gray-lighter !default; 611 | $list-group-disabled-text-color: $list-group-disabled-color !default; 612 | 613 | $list-group-link-color: #555 !default; 614 | $list-group-link-hover-color: $list-group-link-color !default; 615 | $list-group-link-heading-color: #333 !default; 616 | 617 | 618 | // Image thumbnails 619 | 620 | $thumbnail-padding: .25rem !default; 621 | $thumbnail-bg: $body-bg !default; 622 | $thumbnail-border-width: $border-width !default; 623 | $thumbnail-border-color: #ddd !default; 624 | $thumbnail-border-radius: $border-radius !default; 625 | 626 | 627 | // Breadcrumbs 628 | 629 | $breadcrumb-padding-vertical: .75rem !default; 630 | $breadcrumb-padding-horizontal: 1rem !default; 631 | 632 | $breadcrumb-bg: $gray-lighter !default; 633 | $breadcrumb-divider-color: $gray-light !default; 634 | $breadcrumb-active-color: $gray-light !default; 635 | $breadcrumb-divider: "/" !default; 636 | 637 | 638 | // Carousel 639 | 640 | $carousel-text-shadow: 0 1px 2px rgba(0,0,0,.6) !default; 641 | 642 | $carousel-control-color: #fff !default; 643 | $carousel-control-width: 15% !default; 644 | $carousel-control-opacity: .5 !default; 645 | $carousel-control-font-size: 20px !default; 646 | 647 | $carousel-indicator-active-bg: #fff !default; 648 | $carousel-indicator-border-color: #fff !default; 649 | 650 | $carousel-caption-color: #fff !default; 651 | 652 | 653 | // Close 654 | 655 | $close-font-weight: bold !default; 656 | $close-color: #000 !default; 657 | $close-text-shadow: 0 1px 0 #fff !default; 658 | 659 | 660 | // Code 661 | 662 | $code-color: #bd4147 !default; 663 | $code-bg: #f7f7f9 !default; 664 | 665 | $kbd-color: #fff !default; 666 | $kbd-bg: #333 !default; 667 | 668 | $pre-bg: #f7f7f9 !default; 669 | $pre-color: $gray-dark !default; 670 | $pre-border-color: #ccc !default; 671 | $pre-scrollable-max-height: 340px !default; 672 | -------------------------------------------------------------------------------- /web_client/app.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | 4 | import { App } from './components' 5 | 6 | 7 | ReactDOM.render( 8 | , 9 | document.getElementById("app") 10 | ); 11 | -------------------------------------------------------------------------------- /web_client/components/App/index.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { Router, Route, IndexRoute, Link, browserHistory } from 'react-router' 3 | import { BaseLayout } from '../../layouts' 4 | import List from '../List' 5 | import Article from '../Article' 6 | 7 | 8 | class App extends Component { 9 | render(){ 10 | return( 11 | 12 | 13 | 14 | 15 | 16 | 17 | ); 18 | } 19 | } 20 | 21 | 22 | export default App 23 | -------------------------------------------------------------------------------- /web_client/components/Article/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { Link } from 'react-router' 3 | import { format_date } from '../../utils' 4 | 5 | import './style.sass' 6 | 7 | 8 | class Article extends Component { 9 | state = { 10 | title: '', 11 | created_at: '', 12 | text: '' 13 | }; 14 | 15 | loadArticle(article_id) { 16 | fetch(`/api/v0/articles/${article_id}/`) 17 | .then(response => response.json()) 18 | .then(data => { 19 | this.setState(data) 20 | }); 21 | } 22 | 23 | componentDidMount() { 24 | this.loadArticle(this.props.params['article_id']); 25 | } 26 | 27 | render(){ 28 | const { title, created_at, text } = this.state; 29 | return( 30 |
31 |

{ title }

32 |

{ format_date(created_at) }

33 |
34 | Все статьи 35 |
36 | ); 37 | } 38 | 39 | } 40 | 41 | 42 | export default Article 43 | -------------------------------------------------------------------------------- /web_client/components/Article/style.sass: -------------------------------------------------------------------------------- 1 | @import "settings" 2 | @import "mixins" 3 | @import "buttons" 4 | 5 | 6 | .article 7 | padding: $grid-gutter-width 0 8 | 9 | &__button 10 | @extend .btn 11 | @extend .btn-primary 12 | -------------------------------------------------------------------------------- /web_client/components/List/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import ListItem from '../ListItem' 3 | 4 | import './style.sass' 5 | 6 | 7 | class List extends Component { 8 | 9 | state = { 10 | articles: [] 11 | }; 12 | 13 | async loadArticles() { 14 | this.setState({ 15 | articles: await fetch("/api/v0/articles/").then(response =>response.json()) 16 | }) 17 | } 18 | 19 | componentDidMount() { 20 | this.loadArticles(); 21 | } 22 | 23 | render(){ 24 | return( 25 |
    26 | {this.state.articles.map((article, index) => ( 27 |
  • 28 | 29 |
  • 30 | ))} 31 |
32 | ); 33 | } 34 | } 35 | 36 | 37 | export default List 38 | -------------------------------------------------------------------------------- /web_client/components/List/style.sass: -------------------------------------------------------------------------------- 1 | @import "settings" 2 | @import "mixins" 3 | 4 | 5 | .content-list 6 | +list-unstyled() 7 | padding: $grid-gutter-width 0 8 | 9 | &__item 10 | margin-bottom: $grid-gutter-width 11 | transition: all $hover-transition-duration ease 12 | -------------------------------------------------------------------------------- /web_client/components/ListItem/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Link } from 'react-router' 3 | import { format_date } from '../../utils' 4 | 5 | 6 | export default ({ article }) => ( 7 |
8 |

9 | { article.title } 10 |

11 |

{ format_date(article['created_at']) }

12 |
13 |
14 | ) 15 | -------------------------------------------------------------------------------- /web_client/components/index.js: -------------------------------------------------------------------------------- 1 | export { default as App } from './App' 2 | export { default as List } from './List' 3 | -------------------------------------------------------------------------------- /web_client/layouts/BaseLayout/_app_mixins.sass: -------------------------------------------------------------------------------- 1 | @mixin inverse 2 | background: black 3 | &, & a 4 | color: #f90 5 | -------------------------------------------------------------------------------- /web_client/layouts/BaseLayout/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { IndexLink } from 'react-router' 3 | import ReactCSSTransitionGroup from 'react-addons-css-transition-group' 4 | 5 | import './style.sass' 6 | 7 | const LayoutBase = ({ children, location }) => ( 8 |
9 |
10 |
11 |
12 | МегаАпп 13 |
14 |
15 | 22 | {React.cloneElement(children, { 23 | key: location.pathname 24 | })} 25 | 26 |
27 | 30 |
31 | ); 32 | 33 | 34 | export default LayoutBase 35 | -------------------------------------------------------------------------------- /web_client/layouts/BaseLayout/style.sass: -------------------------------------------------------------------------------- 1 | @import "settings" 2 | @import "normalize" 3 | @import "mixins" 4 | @import "reboot" 5 | @import "type" 6 | @import "images" 7 | @import "code" 8 | @import "grid" 9 | 10 | @import "app_mixins" 11 | 12 | html, body, #app 13 | height: 100% 14 | 15 | .app 16 | min-height: 100% 17 | display: flex 18 | flex-direction: column 19 | justify-content: space-between 20 | 21 | &__header, &__footer 22 | +inverse() 23 | height: $header-height 24 | line-height: $header-height 25 | padding: 0 $grid-gutter-width 26 | 27 | &__footer 28 | text-align: center 29 | 30 | &__content 31 | @extend .container 32 | position: relative 33 | perspective: 600px 34 | transform-origin: center 35 | 36 | &_page 37 | &-leave, &-enter 38 | transition: all $transition-duration ease 39 | &-leave 40 | transform: translateX(0px) rotateY(0deg) 41 | &-active 42 | transform: translateX(-600px) rotateY(-45deg) 43 | &-enter 44 | transform: translateX(600px) rotateY(45deg) 45 | position: absolute 46 | &-active 47 | transform: translateX(0px) rotateY(0deg) 48 | 49 | -------------------------------------------------------------------------------- /web_client/layouts/index.js: -------------------------------------------------------------------------------- 1 | export { default as BaseLayout } from './BaseLayout' 2 | -------------------------------------------------------------------------------- /web_client/utils/format_date.js: -------------------------------------------------------------------------------- 1 | export default (date, format="L") => { 2 | var moment = require('moment'); 3 | require('moment/locale/ru'); 4 | return moment(date).format(format) 5 | } 6 | -------------------------------------------------------------------------------- /web_client/utils/index.js: -------------------------------------------------------------------------------- 1 | export { default as format_date } from './format_date' -------------------------------------------------------------------------------- /webpack.config.babel.js: -------------------------------------------------------------------------------- 1 | import path from 'path' 2 | import 'webpack' 3 | import autoprefixer from 'autoprefixer' 4 | 5 | 6 | export default { 7 | entry: './web_client/app.js', 8 | output: { 9 | path: `${__dirname}/main/static`, 10 | filename: 'app.js' 11 | }, 12 | resolve: { 13 | extensions: ['', '.js', '.jsx', '.scss'], 14 | modulesDirectories: [ 15 | 'node_modules' 16 | ] 17 | }, 18 | module: { 19 | loaders: [ 20 | { 21 | test: /\.jsx?$/, 22 | loader: ['babel'], 23 | include: [ 24 | path.resolve(__dirname, "web_client") 25 | ], 26 | query: { 27 | plugins: ['transform-runtime'], 28 | presets: ['es2015', 'stage-0', 'react'] 29 | } 30 | }, 31 | { 32 | test: /\.s[a|c]ss$/, 33 | loaders: [ 34 | 'style', 35 | 'css', 36 | 'postcss', 37 | 'sass' 38 | ] 39 | } 40 | ] 41 | }, 42 | sassLoader: { 43 | includePaths: [ 44 | path.resolve(__dirname, "./web_client"), 45 | path.resolve(__dirname, "./node_modules/bootstrap/scss") 46 | ] 47 | }, 48 | postcss: () => [autoprefixer({ browsers: ['> 1%'] })] 49 | } 50 | --------------------------------------------------------------------------------