Documents serverside
This commit is contained in:
1 parent
244f1efd03
commit
864d895105
17 files changed
+528
-119
No files matched your search
+1
-37
@@ -54,7 +54,7 @@ import API from './services/api'
|
||||
import Theme from './services/theme'
|
||||
|
||||
import {sortByPattern} from '../utils/sort'
|
||||
import {documentsSortPattern, collectiveSortPattern} from './config'
|
||||
import {documentsSortPattern} from './config'
|
||||
|
||||
let app = angular.module('hudozka', [
|
||||
'ngRoute',
|
||||
@@ -92,42 +92,6 @@ app.config(($locationProvider, $routeProvider) => {
|
||||
.list()
|
||||
.then(i => i.data)
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '/awards',
|
||||
template: '<page-awards items="$resolve.awards"></page-awards>',
|
||||
title: 'Награды',
|
||||
resolve: {
|
||||
awards: api => api.document
|
||||
.awards()
|
||||
.then(i => i.data),
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '/documents',
|
||||
template: '<page-documents documents="$resolve.documents"></page-documents>',
|
||||
title: 'Документы',
|
||||
resolve: {
|
||||
documents: api => api.document
|
||||
.documents()
|
||||
.then(i => i.data)
|
||||
.then(i => {
|
||||
return sortByPattern(i, documentsSortPattern, i => i.category)
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '/documents/:id',
|
||||
template: '<page-document item="$resolve.document"></page-document>',
|
||||
resolve: {
|
||||
document: ($route, api) => {
|
||||
let id = $route.current.params.id
|
||||
|
||||
return api.document
|
||||
.id(id)
|
||||
.then(i => i.data)
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
.concat(pages)
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
const React = require('react')
|
||||
const {ext, size} = require('../lib/file')
|
||||
const {titleCase} = require('../lib/string')
|
||||
|
||||
const Document = ({title, url, imageUrl, fileUrl, fileName, fileSize}) => (
|
||||
<div className="document">
|
||||
<div className="document__image">
|
||||
<a href={fileUrl} target="_blank" className="invisible">
|
||||
<img src={imageUrl} alt={title}/>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div className="document__file">
|
||||
<span>{titleCase(title)}</span>
|
||||
</div>
|
||||
|
||||
<div className="document__file-info">
|
||||
<a href={fileUrl} target="_blank">{ext(fileName)} ({size(fileSize)})</a>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
module.exports = Document
|
||||
@@ -0,0 +1,20 @@
|
||||
const React = require('react')
|
||||
const Document = require('./DocumentListItem')
|
||||
|
||||
const DocumentList = ({documents, name}) => (
|
||||
<div className="documents-container">
|
||||
<div className="documents-container__head">
|
||||
<h2>{name}</h2>
|
||||
</div>
|
||||
|
||||
<div className="documents-container__body">
|
||||
{documents.map((d, i) => (
|
||||
<div>
|
||||
<Document key={i} {...d}/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
module.exports = DocumentList
|
||||
@@ -0,0 +1,23 @@
|
||||
const React = require('react')
|
||||
const {ext, size} = require('../lib/file')
|
||||
const {titleCase} = require('../lib/string')
|
||||
|
||||
const Document = ({title, url, imageUrl, fileUrl, fileName, fileSize}) => (
|
||||
<div className="document-row">
|
||||
<a href={url} className="invisible">
|
||||
<div className="document-row__image">
|
||||
<img src={imageUrl} alt={title}/>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<div className="document-row__file">
|
||||
<a href={url}>{titleCase(title)}</a>
|
||||
</div>
|
||||
|
||||
<div className="document-row__file-info">
|
||||
<a href={fileUrl} target="_blank">{ext(fileName)} ({size(fileSize)})</a>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
module.exports = Document
|
||||
@@ -0,0 +1,54 @@
|
||||
const Data = require('./Data')
|
||||
const Image = require('./Image')
|
||||
const {find, findOne} = require('../lib/store')
|
||||
|
||||
const store = () => Data.getStore(Document)
|
||||
|
||||
class Document {
|
||||
static async find(query, options = {}) {
|
||||
const items = await find(store(), query, options)
|
||||
|
||||
return Promise.all(items.map(processDocument))
|
||||
}
|
||||
|
||||
static async findById(id) {
|
||||
const data = await findOne(store(), {id})
|
||||
if (!data) return null
|
||||
|
||||
return processDocument(data)
|
||||
}
|
||||
|
||||
constructor(data) {
|
||||
this.id = data.id
|
||||
this.hash = data.hash
|
||||
this.file = new DocumentFile(data.file)
|
||||
this.type = data.type
|
||||
this.title = data.title
|
||||
this.category = data.category
|
||||
this.url = data.url
|
||||
|
||||
this.preview = data.preview
|
||||
this.viewUrl = `/document/${this.id}`
|
||||
}
|
||||
}
|
||||
|
||||
class DocumentFile {
|
||||
constructor(data) {
|
||||
this.name = data.name
|
||||
this.size = data.size
|
||||
}
|
||||
}
|
||||
|
||||
const
|
||||
processDocument = async data => {
|
||||
const imageId = data.preview
|
||||
const preview = await Image.findById(imageId)
|
||||
|
||||
return new Document({
|
||||
...data,
|
||||
preview,
|
||||
})
|
||||
}
|
||||
|
||||
module
|
||||
.exports = Document
|
||||
@@ -1,6 +1,7 @@
|
||||
const Data = require('./Data')
|
||||
const Album = require('./Album')
|
||||
const Teacher = require('./Teacher')
|
||||
const Document = require('./Document')
|
||||
const Image = require('./Image')
|
||||
|
||||
const {MongoClient, ObjectId} = require('mongodb')
|
||||
@@ -30,6 +31,7 @@ function init(db) {
|
||||
Data.setStore(Album, db.collection('albums'))
|
||||
Data.setStore(Image, db.collection('images'))
|
||||
Data.setStore(Teacher, db.collection('collective'))
|
||||
Data.setStore(Document, db.collection('documents'))
|
||||
|
||||
return db
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
function splitBy(key) {
|
||||
return items => {
|
||||
return items.reduce((acc, item) => {
|
||||
const name = key(item)
|
||||
const items = acc.get(name) || []
|
||||
|
||||
return acc.set(key(item), [...items, item])
|
||||
}, new Map())
|
||||
}
|
||||
}
|
||||
|
||||
exports.splitBy = splitBy
|
||||
@@ -0,0 +1,27 @@
|
||||
function ext(filname) {
|
||||
let getExt = name => /\.(\w+)$/.exec(name)[1]
|
||||
let defaultExt = ext => ext.toUpperCase()
|
||||
|
||||
const exts = ['png', 'pdf', 'jpg', 'jpeg', 'gif', 'doc']
|
||||
const extd = ['ПНГ', 'ПДФ', 'ЖПГ', 'ЖПГ', 'ГИФ', 'ДОК']
|
||||
|
||||
let ext = getExt(filname)
|
||||
const i = exts.indexOf(ext)
|
||||
|
||||
return i > -1
|
||||
? extd[i]
|
||||
: defaultExt(ext)
|
||||
}
|
||||
|
||||
function size(bytes, precision = 1) {
|
||||
if (isNaN(parseFloat(bytes)) || !isFinite(bytes)) return ''
|
||||
|
||||
const units = ['байт', 'КБ', 'МБ', 'ГБ', 'ТБ', 'ПБ']
|
||||
const number = Math.floor(Math.log(bytes) / Math.log(1024))
|
||||
|
||||
const size = (bytes / Math.pow(1024, Math.floor(number))).toFixed(precision)
|
||||
return `${size} ${units[number]}`
|
||||
}
|
||||
|
||||
exports.ext = ext
|
||||
exports.size = size
|
||||
@@ -0,0 +1,12 @@
|
||||
function titleCase(str) {
|
||||
return str.charAt(0).toUpperCase() + str.slice(1)
|
||||
}
|
||||
|
||||
function trim(string) {
|
||||
return string
|
||||
.replace(/^\s+/, '')
|
||||
.replace(/\s+$/, '')
|
||||
}
|
||||
|
||||
exports.titleCase = titleCase
|
||||
exports.trim = trim
|
||||
+6
-3
@@ -56,9 +56,12 @@ export default [
|
||||
]
|
||||
},
|
||||
{
|
||||
'text': 'Документы',
|
||||
'url': '/documents',
|
||||
'color': 'yellow'
|
||||
text: 'Документы',
|
||||
url: '/documents',
|
||||
color: 'yellow',
|
||||
items: [
|
||||
{url: '/document/*', text: ''},
|
||||
]
|
||||
},
|
||||
{
|
||||
url: '/info/',
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
const React = require('react')
|
||||
const Share = require('../components/Share')
|
||||
const DocumentComponent = require('../components/Document')
|
||||
const Document = require('../core/Document')
|
||||
const ImageArtifactType = require('../core/ImageArtifactType')
|
||||
const {render} = require('../lib/render')
|
||||
const {prioritySort} = require('../lib/sort')
|
||||
const getPathWithNoTrailingSlash = require('../lib/url').getPathWithNoTrailingSlash
|
||||
const {get} = require('koa-route')
|
||||
const {splitBy} = require('../lib/array')
|
||||
const {unique} = require('../utils/common')
|
||||
|
||||
const sizes = [
|
||||
ImageArtifactType.MEDIUM,
|
||||
ImageArtifactType.BIG,
|
||||
ImageArtifactType.ORIGIN,
|
||||
]
|
||||
|
||||
function getMeta(document) {
|
||||
return {
|
||||
title: document.title,
|
||||
description: document.title,
|
||||
}
|
||||
}
|
||||
|
||||
async function bakeDocument(document) {
|
||||
//const preview = await document.preview.unpack()
|
||||
const preview = document.preview
|
||||
if (!preview) return null
|
||||
|
||||
const image = preview.findArtifact(sizes)
|
||||
if (!image) return null
|
||||
|
||||
return {
|
||||
category: document.category,
|
||||
title: document.title,
|
||||
fileName: document.file.name,
|
||||
fileSize: document.file.size,
|
||||
fileUrl: document.url,
|
||||
imageUrl: image.url,
|
||||
url: document.viewUrl,
|
||||
}
|
||||
}
|
||||
|
||||
function getDocument() {
|
||||
return get('/document/:id', async (ctx, id) => {
|
||||
const path = getPathWithNoTrailingSlash(ctx.path)
|
||||
const document = await Document.findById(id)
|
||||
const data = document
|
||||
? await bakeDocument(document)
|
||||
: null
|
||||
|
||||
if (data) {
|
||||
const Component = (
|
||||
<div className="content content_wide">
|
||||
<DocumentComponent {...data}/>
|
||||
|
||||
<Share/>
|
||||
</div>
|
||||
)
|
||||
|
||||
ctx.type = 'text/html'
|
||||
ctx.body = await render(path, Component, getMeta(document))
|
||||
} else {
|
||||
ctx.status = 404
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function getSorted(documents) {
|
||||
const compose = (...fns) => value => fns
|
||||
.map(fn => fn)
|
||||
.reverse()
|
||||
.reduce((acc, fn) => fn(acc), value)
|
||||
|
||||
const pass = fn => value => {
|
||||
fn(value)
|
||||
return value
|
||||
}
|
||||
|
||||
const subtract = (a, b) => a - b
|
||||
|
||||
const uniqueCategories = unique(i => i.category)
|
||||
|
||||
const priority = {
|
||||
'Основные документы': [
|
||||
'https://static.shlisselburg.org/art/uploads/ustav-2015.pdf',
|
||||
'https://static.shlisselburg.org/art/uploads/obrazovatelnaia-litsenziia-2015.pdf',
|
||||
'https://static.shlisselburg.org/art/uploads/svidetelstvo-na-pomeshchenie.pdf',
|
||||
'https://static.shlisselburg.org/art/uploads/egriul.pdf',
|
||||
'https://static.shlisselburg.org/art/uploads/inn.pdf',
|
||||
'https://static.shlisselburg.org/art/uploads/reshenie-o-sozdanii-shkoly.pdf',
|
||||
'https://static.shlisselburg.org/art/uploads/kopiia-resheniia-o-naznachenii-rukovoditelia.pdf',
|
||||
'https://static.shlisselburg.org/art/uploads/postanovlenie-o-sozdanii-munitsipalnogo-obrazovatelnogo-uchrezhdeniia-kultury-detskaia-khudozhestvennaia-shkola.pdf',
|
||||
],
|
||||
'Учебные программы': [
|
||||
'https://static.shlisselburg.org/art/uploads/uchebnaia-programma-zhivopis.pdf',
|
||||
]
|
||||
}
|
||||
|
||||
const CATEGORY_PRIORITY = [
|
||||
'Основные документы',
|
||||
'Планы ФХД',
|
||||
'Самообследование деятельности',
|
||||
'Инструкции',
|
||||
'Образование',
|
||||
'Учебные программы',
|
||||
'Платные образовательные услуги',
|
||||
'Дополнительные общеразвивающие программы',
|
||||
'Документы для поступления',
|
||||
]
|
||||
|
||||
const sortBy = fn => (a, b) => [a, b]
|
||||
.map(fn)
|
||||
.reduce(subtract)
|
||||
|
||||
const getPriorityFn = (m, list) => value => list.includes(value)
|
||||
? list.indexOf(value)
|
||||
: m
|
||||
|
||||
const safeSelect = (d, store, key) => key in store
|
||||
? store[key]
|
||||
: d
|
||||
|
||||
const categoryPriority = getPriorityFn(10000, CATEGORY_PRIORITY)
|
||||
|
||||
const documentPriority = ({category, fileUrl}) => compose(
|
||||
getPriorityFn.bind(null, 10000),
|
||||
safeSelect.bind(null, [], priority)
|
||||
)(category)(fileUrl)
|
||||
|
||||
const documentsOf = category => documents.filter(i => i.category === category)
|
||||
const sorted = documents => documents.sort(sortBy(documentPriority))
|
||||
const collectDocumentsByCategory = compose(sorted, documentsOf)
|
||||
|
||||
return uniqueCategories(documents)
|
||||
.sort(sortBy(categoryPriority))
|
||||
.reduce((acc, name) => [...acc, {
|
||||
name,
|
||||
items: collectDocumentsByCategory(name)
|
||||
}], [])
|
||||
}
|
||||
|
||||
exports.getDocument = getDocument
|
||||
+137
-64
@@ -1,82 +1,155 @@
|
||||
import compose from 'koa-compose'
|
||||
import route from 'koa-route'
|
||||
import {index, json, accepts} from './'
|
||||
import {c} from '../core/db'
|
||||
const React = require('react')
|
||||
const Article = require('../components/Article')
|
||||
const DocumentList = require('../components/DocumentList')
|
||||
const Document = require('../core/Document')
|
||||
const ImageArtifactType = require('../core/ImageArtifactType')
|
||||
const {render} = require('../lib/render')
|
||||
const {prioritySort} = require('../lib/sort')
|
||||
const getPathWithNoTrailingSlash = require('../lib/url').getPathWithNoTrailingSlash
|
||||
const {get} = require('koa-route')
|
||||
const {splitBy} = require('../lib/array')
|
||||
const {unique} = require('../utils/common')
|
||||
|
||||
async function exists(ctx, id) {
|
||||
let i = await c('documents').findOne({id: id})
|
||||
return Boolean(i)
|
||||
const sizes = [
|
||||
ImageArtifactType.MEDIUM,
|
||||
ImageArtifactType.BIG,
|
||||
ImageArtifactType.ORIGIN,
|
||||
]
|
||||
|
||||
function getDocumentsMeta() {
|
||||
return {
|
||||
title: 'Документы',
|
||||
description: 'Документы Шлиссельбургской ДХШ',
|
||||
}
|
||||
}
|
||||
|
||||
export default function (store) {
|
||||
return compose([
|
||||
docs(store),
|
||||
documents(),
|
||||
document(),
|
||||
type()
|
||||
])
|
||||
function getMeta(teacher) {
|
||||
return {
|
||||
title: teacher.name,
|
||||
description: teacher.name,
|
||||
}
|
||||
}
|
||||
|
||||
function docs(store) {
|
||||
return route.get('/docs', async ctx => {
|
||||
const docs = await store.document.find({})
|
||||
ctx.body = docs
|
||||
})
|
||||
async function bakeDocument(document) {
|
||||
//const preview = await document.preview.unpack()
|
||||
const preview = document.preview
|
||||
if (!preview) return null
|
||||
|
||||
const image = preview.findArtifact(sizes)
|
||||
if (!image) return null
|
||||
|
||||
return {
|
||||
category: document.category,
|
||||
title: document.title,
|
||||
fileName: document.file.name,
|
||||
fileSize: document.file.size,
|
||||
fileUrl: document.url,
|
||||
imageUrl: image.url,
|
||||
url: document.viewUrl,
|
||||
}
|
||||
}
|
||||
|
||||
function documents() {
|
||||
return route.get('/documents', json(
|
||||
async(ctx) => {
|
||||
let query = {}
|
||||
ctx.body = await c('documents')
|
||||
.find(query)
|
||||
.toArray()
|
||||
}
|
||||
))
|
||||
}
|
||||
function getDocuments() {
|
||||
return get('/documents', async (ctx) => {
|
||||
const path = getPathWithNoTrailingSlash(ctx.path)
|
||||
let documents = await Document.find({})
|
||||
|
||||
function document() {
|
||||
return route.get('/documents/:id', accepts({
|
||||
'text/html': index(exists),
|
||||
'text/plain': index(exists),
|
||||
'application/json': async(ctx, id) => {
|
||||
let i = await c('documents').findOne({id: id})
|
||||
if (!i) ctx.status = 404
|
||||
else {
|
||||
i = await populateDocPreview(i)
|
||||
ctx.body = i
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
if (documents) {
|
||||
//documents = teachersSorted(documents)
|
||||
documents = await Promise.all(documents.map(bakeDocument))
|
||||
documents = documents.filter(Boolean)
|
||||
|
||||
function type() {
|
||||
return route.get('/documents/type/:type', async(ctx, type) => {
|
||||
let types = {
|
||||
'document': ['documents', {type: 'document'}, populateDocPreview],
|
||||
'award': ['awards', {type: 'award'}, populateDocPreview]
|
||||
}
|
||||
//const collections = splitBy(d => d.category)(documents)
|
||||
const collections = getSorted(documents)
|
||||
|
||||
if (type in types) {
|
||||
let [collection, query, mapFn] = types[type]
|
||||
const Component = (
|
||||
<div className="content content_thin">
|
||||
{collections.map(({name, items}, index) => (
|
||||
<DocumentList key={index} name={name} documents={items}/>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
|
||||
let docs = await c(collection)
|
||||
.find(query)
|
||||
.toArray()
|
||||
|
||||
if (mapFn) {
|
||||
docs = await Promise.all(
|
||||
docs.map(mapFn)
|
||||
) }
|
||||
|
||||
ctx.body = docs
|
||||
ctx.type = 'text/html'
|
||||
ctx.body = await render(path, Component, getDocumentsMeta())
|
||||
} else {
|
||||
ctx.status = 404
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function populateDocPreview(doc) {
|
||||
doc.preview = await c('images').findOne({_id: doc.preview})
|
||||
return doc
|
||||
function getSorted(documents) {
|
||||
const compose = (...fns) => value => fns
|
||||
.map(fn => fn)
|
||||
.reverse()
|
||||
.reduce((acc, fn) => fn(acc), value)
|
||||
|
||||
const pass = fn => value => {
|
||||
fn(value)
|
||||
return value
|
||||
}
|
||||
|
||||
const subtract = (a, b) => a - b
|
||||
|
||||
const uniqueCategories = unique(i => i.category)
|
||||
|
||||
const priority = {
|
||||
'Основные документы': [
|
||||
'https://static.shlisselburg.org/art/uploads/ustav-2015.pdf',
|
||||
'https://static.shlisselburg.org/art/uploads/obrazovatelnaia-litsenziia-2015.pdf',
|
||||
'https://static.shlisselburg.org/art/uploads/svidetelstvo-na-pomeshchenie.pdf',
|
||||
'https://static.shlisselburg.org/art/uploads/egriul.pdf',
|
||||
'https://static.shlisselburg.org/art/uploads/inn.pdf',
|
||||
'https://static.shlisselburg.org/art/uploads/reshenie-o-sozdanii-shkoly.pdf',
|
||||
'https://static.shlisselburg.org/art/uploads/kopiia-resheniia-o-naznachenii-rukovoditelia.pdf',
|
||||
'https://static.shlisselburg.org/art/uploads/postanovlenie-o-sozdanii-munitsipalnogo-obrazovatelnogo-uchrezhdeniia-kultury-detskaia-khudozhestvennaia-shkola.pdf',
|
||||
],
|
||||
'Учебные программы': [
|
||||
'https://static.shlisselburg.org/art/uploads/uchebnaia-programma-zhivopis.pdf',
|
||||
]
|
||||
}
|
||||
|
||||
const CATEGORY_PRIORITY = [
|
||||
'Основные документы',
|
||||
'Планы ФХД',
|
||||
'Самообследование деятельности',
|
||||
'Инструкции',
|
||||
'Образование',
|
||||
'Учебные программы',
|
||||
'Платные образовательные услуги',
|
||||
'Дополнительные общеразвивающие программы',
|
||||
'Документы для поступления',
|
||||
]
|
||||
|
||||
const sortBy = fn => (a, b) => [a, b]
|
||||
.map(fn)
|
||||
.reduce(subtract)
|
||||
|
||||
const getPriorityFn = (m, list) => value => list.includes(value)
|
||||
? list.indexOf(value)
|
||||
: m
|
||||
|
||||
const safeSelect = (d, store, key) => key in store
|
||||
? store[key]
|
||||
: d
|
||||
|
||||
const categoryPriority = getPriorityFn(10000, CATEGORY_PRIORITY)
|
||||
|
||||
const documentPriority = ({category, fileUrl}) => compose(
|
||||
getPriorityFn.bind(null, 10000),
|
||||
safeSelect.bind(null, [], priority)
|
||||
)(category)(fileUrl)
|
||||
|
||||
const documentsOf = category => documents.filter(i => i.category === category)
|
||||
const sorted = documents => documents.sort(sortBy(documentPriority))
|
||||
const collectDocumentsByCategory = compose(sorted, documentsOf)
|
||||
|
||||
return uniqueCategories(documents)
|
||||
.sort(sortBy(categoryPriority))
|
||||
.reduce((acc, name) => [...acc, {
|
||||
name,
|
||||
items: collectDocumentsByCategory(name)
|
||||
}], [])
|
||||
}
|
||||
|
||||
exports.getDocuments = getDocuments
|
||||
@@ -7,14 +7,12 @@ import {index as indexFile} from '../config'
|
||||
|
||||
import sitemap from './sitemap'
|
||||
import schedule from './schedule'
|
||||
import documents from './documents'
|
||||
import pages from './pages'
|
||||
|
||||
export function routes(store) {
|
||||
return compose([
|
||||
sitemap(),
|
||||
schedule(),
|
||||
documents(store),
|
||||
pages(),
|
||||
])
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ const article = require('./routes/articles')
|
||||
const albums = require('./routes/albums')
|
||||
const gallery = require('./routes/gallery')
|
||||
const teachers = require('./routes/teachers')
|
||||
const documents = require('./routes/documents')
|
||||
const document = require('./routes/document')
|
||||
|
||||
const dirPublic = path.join(__dirname, '../public')
|
||||
const dirTemplates = path.join(__dirname, 'templates')
|
||||
@@ -70,6 +72,8 @@ export default function (store) {
|
||||
app.use(albums.getAlbum())
|
||||
app.use(teachers.getCollective(collectiveOrder))
|
||||
app.use(teachers.getTeacher())
|
||||
app.use(documents.getDocuments())
|
||||
app.use(document.getDocument())
|
||||
app.use(routes(store))
|
||||
|
||||
return Server(app.callback())
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
@import "../variables";
|
||||
|
||||
.document-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding: 0;
|
||||
margin-bottom: $single-margin;
|
||||
}
|
||||
|
||||
.document-row__image{
|
||||
min-width: 4em;
|
||||
width: 4em;
|
||||
height: 4em;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
//align-items: center;
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
box-shadow: $white-shadow;
|
||||
}
|
||||
}
|
||||
|
||||
.document-row__image--medium{
|
||||
}
|
||||
|
||||
.document-row__image--big{
|
||||
max-width: 20em;
|
||||
}
|
||||
|
||||
.document-row__file {
|
||||
margin-left: $single-margin;
|
||||
flex-grow: 10;
|
||||
}
|
||||
|
||||
.document-row__file-info {
|
||||
width: 25%;
|
||||
flex-grow: 1;
|
||||
font-size: $smaller-font-size;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
@media (max-width: $mobile-width) {
|
||||
.document-row {
|
||||
margin: 0 $single-margin/2 $single-margin;
|
||||
}
|
||||
}
|
||||
@@ -2,19 +2,22 @@
|
||||
|
||||
.document {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 0;
|
||||
margin-bottom: $single-margin;
|
||||
margin-bottom: $double-margin;
|
||||
}
|
||||
|
||||
.document__image{
|
||||
min-width: 4em;
|
||||
width: 4em;
|
||||
height: 4em;
|
||||
//min-width: 10em;
|
||||
//width: 20em;
|
||||
//height: 20em;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
margin-bottom: $single-margin;
|
||||
|
||||
//display: flex;
|
||||
//justify-content: center;
|
||||
//align-items: flex-start;
|
||||
//align-items: center;
|
||||
|
||||
img {
|
||||
@@ -32,15 +35,11 @@
|
||||
}
|
||||
|
||||
.document__file {
|
||||
margin-left: $single-margin;
|
||||
flex-grow: 10;
|
||||
|
||||
}
|
||||
|
||||
.document__file-info {
|
||||
width: 25%;
|
||||
flex-grow: 1;
|
||||
font-size: $smaller-font-size;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
@media (max-width: $mobile-width) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
@import "components/album-collection";
|
||||
@import "components/gallery-item";
|
||||
@import "components/document";
|
||||
@import "components/document-row";
|
||||
@import "components/documents-container";
|
||||
@import "components/teacher-proifile";
|
||||
@import "components/main-menu";
|
||||
|
||||
Reference in new issue
Block a user