+ CLOUD PAGES; style updated; other changes

This commit is contained in:
tmshv committed 2016-11-12 05:17:10 +03:00
1 parent dad12f52f4
commit edf5fbf4bd
27 files changed
+339 -161

No files matched your search

+4 -2
View File
@@ -21,14 +21,16 @@
"angular": "^1.5.3",
"angular-route": "^1.5.3",
"angular-spinner": "^0.8.1",
"angulartics": "^1.2.1",
"angulartics-google-analytics": "^0.1.4",
"angulartics": "^1.0.0",
"angulartics-google-analytics": "^0.3.0",
"async-file": "^2.0.2",
"babel-core": "^6.7.4",
"babel-polyfill": "^6.7.4",
"babel-preset-es2015": "^6.5.0",
"babel-preset-stage-0": "^6.5.0",
"co": "^4.4.0",
"ejson": "^2.1.2",
"handlebars": "^4.0.5",
"hudozka-api-v1": "file:modules/hudozka-api-v1",
"hudozka-data": "file:modules/hudozka-data",
"hudozka-middlewares": "file:modules/hudozka-middlewares",
+2
View File
@@ -5,6 +5,7 @@ import APITeacher from './APITeacher';
import APISchedule from './APISchedule';
import APIEvent from './APIEvent';
import APIArticle from './APIArticle';
import APIPage from './APIPage';
export default class API {
constructor(request) {
@@ -15,5 +16,6 @@ export default class API {
this.schedule = new APISchedule(request);
this.event = new APIEvent(request);
this.article = new APIArticle(request);
this.page = new APIPage(request);
}
}
+7
View File
@@ -0,0 +1,7 @@
import EndPoint from './EndPoint';
export default class APIPage extends EndPoint {
url(url) {
return this.get(url);
}
}
+19
View File
@@ -1,3 +1,4 @@
import {getInitialData} from './core/init';
import Navigation from './components/Navigation';
import MainMenu from './components/MainMenu';
import Breadcrumbs from './components/Breadcrumbs';
@@ -20,6 +21,7 @@ import ArticlePageControl from './components/ArticlePageControl';
import Album from './components/Album';
import Parallax from './components/Parallax';
import Page from './components/CloudPage';
import PageSchool from './components/PageSchool';
import PageEvents from './components/PageEvents';
import PageArticle from './components/PageArticle';
@@ -61,6 +63,21 @@ app.config(($locationProvider, $routeProvider) => {
$locationProvider.hashPrefix('!');
$locationProvider.html5Mode(true);
const pages = getInitialData().pages
.map(i => i.url)
.map(i => ({
name: i,
template: '<cloud-page data="$.data"></cloud-page>',
resolveAs: '$',
resolve: {
data: (api) => {
return api.page
.url(location.pathname)
.then(i => i.data)
}
}
}));
let routers = [
{
name: '/',
@@ -191,6 +208,7 @@ app.config(($locationProvider, $routeProvider) => {
}
}
]
.concat(pages)
.map(i => {
let path = i.name;
delete i.name;
@@ -264,6 +282,7 @@ app.run(($location, $rootScope, $http) => {
GalleryItem,
AlbumCollection,
TeacherProfile,
Page,
PageSchool,
PageArticle,
PageEvents,
+15
View File
@@ -0,0 +1,15 @@
import template from '../../templates/components/cloud-page.html';
export default function (app) {
app.component('cloudPage', {
bindings: {
page: '<data'
},
template: template,
controllerAs: '$',
controller: function ($rootScope, $sce) {
if (this.page) $rootScope.title = this.page.title;
this.content = $sce.trustAsHtml(this.page.data);
}
});
};
-32
View File
@@ -40,38 +40,6 @@ export const footer = {
{url: '/document/VAT', link: 'ИНН'},
{url: '/document/statue-2013', link: 'Устав школы'}
]
},
sites: {
title: 'Ссылки на образовательные сайты',
links: [
{
url: 'http://минобрнауки.рф',
link: 'минобрнауки.рф',
description: 'Министерство образования и науки Российской Федерации'
},
{url: 'http://edu.ru', link: 'edu.ru', description: 'Федеральный сайт «Российское образование»'},
{
url: 'http://window.edu.ru',
link: 'window.edu.ru',
description: 'Единое окно доступа к образовательным ресурсам'
},
{
url: 'http://school-collection.edu.ru',
link: 'school-collection.edu.ru',
description: 'Единая коллекция цифровых образовательных ресурсов'
},
{
url: 'http://fcior.edu.ru',
link: 'fcior.edu.ru',
description: 'Федеральный центр информационных образовательных ресурсов'
},
{url: 'http://dkhshmga.ru', link: 'dkhshmga.ru', description: 'Художественная школа Мги'},
{
url: 'http://kirovskdmh.ucoz.ru',
link: 'kirovskdmh.ucoz.ru',
description: 'Музыкальная школа Кировска'
}
]
}
}
};
+3
View File
@@ -0,0 +1,3 @@
export function getInitialData(){
return window.hudozka;
}
+2 -2
View File
@@ -4,11 +4,10 @@ import path from 'path';
const privateFile = process.env['PRIVATE'] || 'private.json';
const privateData = JSON.parse(fs.readFileSync(privateFile, 'utf-8'));
const index_file = process.env['INDEX'] || 'templates/main.html';
const indexFile = process.env['INDEX'] || 'templates/main.html';
const port = process.env['PORT'] || 1800;
const config = {
defaultIndex: path.join(__dirname, index_file),
port: port,
pub: './',
@@ -47,6 +46,7 @@ export const host = 'art.shlisselburg.org';
export const protocol = 'https://';
export const homeUrl = protocol + host;
export const index = path.join(__dirname, indexFile);
export const sitemapCacheTime = 600000;// 600 sec - cache purge period
export const instagramToken = privateData['instagramToken'];
+19
View File
@@ -0,0 +1,19 @@
import {c} from '../core/db';
const PAGES = 'pages';
export async function getPageUrls() {
return await c(PAGES)
.find({}, {url: 1})
.toArray();
}
/**
* Find a person by it's id
*
* @param {string} url
* @returns {Promise|*}
*/
export async function getPage(url) {
return await c(PAGES).findOne({url: url});
}
+5 -4
View File
@@ -14,10 +14,6 @@ export default [
"url": "/schedule",
"color": "green"
},
{
"text": "Занятия",
"color": ""
},
{
"text": "Коллектив",
"url": "/collective",
@@ -32,5 +28,10 @@ export default [
"text": "Документы",
"url": "/documents",
"color": "yellow"
},
{
"text": "Сведения об образовательной организации",
"url": "/info",
"color": "red"
}
];
+66 -55
View File
@@ -1,12 +1,14 @@
import fs from 'mz/fs';
import {readFile} from 'async-file';
import handlebars from 'handlebars';
import route from 'koa-route';
import compose from 'koa-compose';
import {map, assign} from '../utils/common';
import config from '../config';
import {index as indexFile} from '../config';
import sitemap from './sitemap';
import schedule from './schedule';
import {getPageUrls} from '../core/pages';
import news from './news';
import gallery from './gallery';
import error404 from './404';
@@ -14,77 +16,86 @@ import documents from './documents';
import teachers from './teachers';
import events from './events';
import articles from './articles';
import pages from './pages';
let main = () => route.get('/', index());
export function routes(){
return compose([
main(),
sitemap(),
schedule(),
news(),
gallery(),
documents(),
teachers(),
events(),
articles(),
error404()
]);
export function routes() {
return compose([
main(),
sitemap(),
schedule(),
news(),
gallery(),
documents(),
teachers(),
events(),
articles(),
pages(),
error404()
]);
}
export function queryObject() {
let toTrue = map(true, i => i === 'true');
let toFalse = map(false, i => i === 'false');
const processors = [toTrue, toFalse];
let toTrue = map(true, i => i === 'true');
let toFalse = map(false, i => i === 'false');
const processors = [toTrue, toFalse];
return async (ctx, next) => {
let query = ctx.query;
ctx.query = Object.keys(query)
.reduce((query, key) => assign(
query,
key,
processors
.reduce((value, fn) => fn(value), query[key])
), query);
return async(ctx, next) => {
let query = ctx.query;
ctx.query = Object
.keys(query)
.reduce((query, key) => assign(
query,
key,
processors
.reduce((value, fn) => fn(value), query[key])
), query);
await next();
}
await next();
}
}
export function accepts(routes) {
return async function (ctx) {
let request = ctx.request;
let types = Object.keys(routes)
.filter(type => request.accepts(type));
return async function (ctx) {
let request = ctx.request;
let types = Object.keys(routes)
.filter(type => request.accepts(type));
if (types.length) {
let fn = routes[types[0]];
if (types.length) {
let fn = routes[types[0]];
await fn.apply(ctx, arguments);
} else {
ctx.status = 406;
}
};
await fn.apply(ctx, arguments);
} else {
ctx.status = 406;
}
};
}
export function index(fn) {
let filename = config['defaultIndex'];
return async function (ctx) {
let test = true;
if (fn) test = await fn.apply(ctx, arguments);
if (!test) ctx.status = 404;
return async function (ctx){
let test = true;
if (fn) test = await fn.apply(ctx, arguments);
const data = await getInitialData();
const source = await readFile(indexFile, 'utf-8');
const template = handlebars.compile(source);
if (!test) ctx.status = 404;
ctx.type = 'text/html';
ctx.body = fs.createReadStream(filename);
}
ctx.type = 'text/html';
ctx.body = template({data: JSON.stringify(data)});
}
}
export function json(fn){
return accepts({
'text/html': index(),
'text/plain': index(),
'application/json': fn
});
export function json(fn) {
return accepts({
'text/html': index(),
'text/plain': index(),
'application/json': fn
});
}
async function getInitialData() {
const pages = await getPageUrls();
return {pages: pages};
}
+24
View File
@@ -0,0 +1,24 @@
import route from 'koa-route';
import {c} from '../core/db';
import {accepts, index} from './';
async function exists(ctx) {
const page = await getPage(ctx.path);
return Boolean(page);
}
async function getPage(path) {
return await c('pages').findOne({url: path});
}
export default function () {
return route.get('*', accepts({
'text/html': index(exists),
'text/plain': index(exists),
'application/json': async(ctx) => {
const page = await getPage(ctx.path);
if (!page) ctx.status = 404;
else ctx.body = page;
}
}))
};
+41 -39
View File
@@ -6,61 +6,63 @@ import logger from 'koa-logger';
import convert from 'koa-convert';
import conditional from 'koa-conditional-get';
import etag from 'koa-etag';
// import prerender from 'koa-prerender';
import prerender from 'koa-prerender';
import helmet from 'koa-helmet';
import mount from 'koa-mount';
import bodyParser from 'koa-bodyparser';
import api_v1 from 'hudozka-api-v1';
import config from './config';
import {redirectionTable} from './config';
import apiV1 from 'hudozka-api-v1';
import config, {redirectionTable} from './config';
import {routes, queryObject} from './routes';
import {redirect} from './routes/redirect';
import {services as serviceKeys, authChecker} from './core/service';
import handlebars from 'handlebars';
const dirPublic = path.join(__dirname, '../public');
const dirTemplates = path.join(__dirname, 'templates');
export default function(store){
const $ = convert;
const app = new Koa();
app.proxy = true;
handlebars.registerHelper('raw-helper', options => options.fn());
app.use(bodyParser({
extendTypes: {
json: 'application/ejson'
}
}));
app.use(logger());
app.use(apis(store));
app.use($(conditional()));
app.use($(etag()));
// app.use(prerenderRmFragment());
// app.use($(prerender(config.prerender)));
app.use(serve(dirPublic));
app.use(serve(dirTemplates));
app.use($(redirect(redirectionTable)));
app.use($(helmet()));
app.use(queryObject());
app.use(routes());
export default function (store) {
const $ = convert;
return Server(app.callback());
const app = new Koa();
app.proxy = true;
app.use(bodyParser({
extendTypes: {
json: 'application/ejson'
}
}));
app.use(logger());
app.use(apis(store));
app.use($(conditional()));
app.use($(etag()));
app.use(prerenderRmFragment());
app.use($(prerender(config.prerender)));
app.use(serve(dirPublic));
app.use(serve(dirTemplates));
app.use($(redirect(redirectionTable)));
app.use($(helmet()));
app.use(queryObject());
app.use(routes());
return Server(app.callback());
}
function apis(store){
let checkAuth = authChecker(serviceKeys);
return mount('/api/v1', api_v1(checkAuth, store));
function apis(store) {
let checkAuth = authChecker(serviceKeys);
return mount('/api/v1', apiV1(checkAuth, store));
}
function prerenderRmFragment(){
return async (ctx, next) => {
await next();
function prerenderRmFragment() {
return async(ctx, next) => {
await next();
try {
let xp = ctx.response.header['x-prerender'] == 'true';
if (xp) ctx.body = ctx.body.replace('<meta name="fragment" content="!">', '');
} catch (e) {
}
}
try {
let xp = ctx.response.header['x-prerender'] === 'true';
if (xp) ctx.body = ctx.body.replace('<meta name="fragment" content="!">', '');
} catch (e) {
}
}
}
+3
View File
@@ -2,6 +2,9 @@
.body-wrapper {
background-color: white;
font-family: $text-font;
font-size: $default-font-size;
}
.body-wrapper__content {
+1 -1
View File
@@ -7,7 +7,7 @@
margin-bottom: 1.25em;
h3 {
font-size: $big-font-size;
font-size: $biggest-font-size;
text-align: center;
}
+8 -5
View File
@@ -7,7 +7,7 @@
margin-bottom: 1.25em;
h3 {
font-size: $big-font-size;
font-size: $biggest-font-size;
text-align: center;
}
@@ -33,13 +33,16 @@
margin: 1.25em auto $small-margin;
}
ul{
margin-bottom: 1.25em;
list-style: none;
ul, ol{
margin-left: $half-margin;
margin-bottom: $single-margin;
padding-left: $single-margin;
}
ul{
list-style: disc;
}
p{
margin-bottom: 1.25em;
}
+79
View File
@@ -0,0 +1,79 @@
@import "../variables";
.cloud-page {
margin-bottom: $post-margin;
&__body{
a {
color: $dark-color;
text-decoration: none;
border-bottom: 1px solid lighten($dark-color, 10%);
&:hover {
border-bottom: 1px solid lighten($dark-color, 25%);
}
&:active {
border-bottom: 1px solid $dark-color;
}
}
h1{
text-align: center;
margin-bottom: $single-margin;
font-size: $biggest-font-size;
}
h2 {
text-align: left;
margin-top: $double-margin;
font-family: $text-font;
}
ul, ol{
margin-left: $half-margin;
margin-bottom: $single-margin;
padding-left: $single-margin;
}
ul{
list-style: disc;
}
p{
margin-bottom: 1.25em;
}
blockquote {
background-color: hsl(215, 10%, 96%);
padding: 1em 1em .5em;
margin: $single-margin 0;
font-family: $title-font;
font-style: italic;
font-weight: normal;
font-size: 1.25em;
cite {
margin-top: $single-margin;
display: block;
color: #aaa;
font-size: initial;
font-family: $text-font;
text-align: right;
margin-right: $single-margin;
}
}
}
}
@media (max-width: $mobile-width) {
.cloud-page {
&__body {
img {
max-height: 20em;
}
}
}
}
+1 -1
View File
@@ -3,7 +3,7 @@
.main-menu {
white-space: nowrap;
font-size: 1.1em;
font-size: $normal-font-size;
color: $menu-inactive-item-color;
list-style: none;
@@ -4,8 +4,6 @@
margin: 0 0 $post-margin;
.date {
//margin: 0 0 0.45em;
//font-size: 0.75em;
color: $light-color;
}
}
+4 -4
View File
@@ -10,7 +10,7 @@
display: flex;
justify-content: center;
button.more{
button.more {
position: relative;
top: -2px;
@@ -20,13 +20,13 @@
padding: 0 10px;
background: none;
font-size: 14pt;
font-size: $normal-font-size;
&:hover{
&:hover {
background: gainsboro;
}
&:active{
&:active {
top: 0;
}
}
+2
View File
@@ -9,6 +9,8 @@ footer {
position: relative;
background-color: $darker-color;
font-size: $smaller-font-size;
&:before {
$s: 3px;
+3 -4
View File
@@ -8,20 +8,19 @@
p {
color: $light-color;
margin-bottom: $single-margin;
font-size: $smaller-font-size;
}
h1 {
margin-top: $single-margin;
font-size: 2em;
font-size: $biggest-font-size;
}
}
@media (max-width: $mobile-width) {
.hudozka-title {
text-align: center;
h1 {
font-size: 1.5em;
font-size: $big-font-size;
}
}
}
-1
View File
@@ -10,7 +10,6 @@ html, body {
}
body {
font-family: $text-font;
min-width: 320px;
}
+1
View File
@@ -11,6 +11,7 @@
@import "components/timeline-record-instagram";
@import "components/schedule-table";
@import "components/footer-links";
@import "components/cloud-page";
@import "components/article";
@import "components/article-page-control";
@import "components/album";
+20 -7
View File
@@ -16,7 +16,7 @@ $embed-video-ratio: 56.25%;
$small-margin: .2em;
$half-margin: .5em;
$single-margin: 1.0em;
$double-margin: 3.0em;
$double-margin: 2.0em;
$post-margin: 5.0em;
//COLOR
@@ -44,15 +44,28 @@ $white-shadow: 0 .1em 0.3em rgba(0, 0, 0, 0.2);
$title-font: "PT Serif", Georgia, serif;
$text-font: "PT Sans", Arial, sans-serif;
$normal-font-size: 1em;
$bigger-font-size: 1.2em;
$big-font-size: 1.75em;
$smaller-font-size: .8em;
$default-font-size: 14pt;
$smaller-font-size: 0.9rem;
$normal-font-size: 1.0rem;
$bigger-font-size: 1.2rem;
$big-font-size: 1.5rem;
$biggest-font-size: 2.5rem;
//MENU
$menu-thickness: 2.5em;
$menu-colored-mark-thickness: 4px;
$menu-colored-mark-thickness: 2px;
$menu-inactive-item-color: hsl(0, 0%, 50%);
//ANIMATION
$short-duration: 0.3s;
$short-duration: 0.3s;
@media (max-width: $mobile-width) {
//FONTS
$default-font-size: 14pt;
$smaller-font-size: 0.9rem;
$normal-font-size: 1.0rem;
$bigger-font-size: 1.1rem;
$big-font-size: 1.3rem;
$biggest-font-size: 2.0rem;
}
+3
View File
@@ -0,0 +1,3 @@
<section class="content content_thin content--padding-top--menu">
<div class="cloud-page__body" ng-bind-html="$.content"></div>
</section>
+7 -2
View File
@@ -48,7 +48,11 @@
//ga('send', 'pageview');
}
</script>
<script>window.hudozka={{{data}}}</script>
</head>
{{{{raw-helper}}}}
<body>
<div class="body-wrapper" ng-controller="AppController">
<header ng-switch="navigation">
@@ -62,7 +66,6 @@
<footer>
<div class="footer-info">
<footer-links title="{{footer.links.docs.title}}" links="footer.links.docs.links"></footer-links>
<footer-links title="{{footer.links.sites.title}}" links="footer.links.sites.links"></footer-links>
</div>
<div class="contacts" ng-controller="ContactsController">
@@ -77,7 +80,7 @@
</div>
<div class="copyright" ng-controller="CopyrightController">
<span>©&nbsp;2012...{{now}} Шлиссельбургская Детская Художественная Школа</span>
<span>©&nbsp;2012—{{now}} Шлиссельбургская Детская Художественная Школа</span>
<span ng-show="developer">Разработка и поддержка сайта — <a href="http://tmshv.ru?utm_source=artshburg&utm_medium=developer&utm_campaign=tmshv_ru">www.tmshv.ru</a></span>
</div>
</footer>
@@ -93,4 +96,6 @@
})();
</script>
</body>
{{{{/raw-helper}}}}
</html>