Merge pull request #9 from tmshv/feature/next-static-export
Next static export
This commit is contained in:
97 files changed
+3441
-12463
No files matched your search
+2
-1
@@ -18,4 +18,5 @@ dist
|
||||
**/*.pyc
|
||||
/coverage
|
||||
**/.vscode
|
||||
*.log
|
||||
*.log
|
||||
.now
|
||||
+5
-4
@@ -1,4 +1,5 @@
|
||||
utils
|
||||
scripts
|
||||
test
|
||||
src
|
||||
.forestry
|
||||
./utils
|
||||
modules
|
||||
data
|
||||
uploads
|
||||
@@ -4,7 +4,7 @@ import { getPathWithNoTrailingSlash } from '../lib/url'
|
||||
import { encodePage } from '../factory/page'
|
||||
|
||||
export async function getItem(req: Request, res: Response) {
|
||||
const id = req.params.slug
|
||||
const id = req.query.page
|
||||
const page = getPathWithNoTrailingSlash(id)
|
||||
const resource = await Page.findByUrl(page)
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ async function main() {
|
||||
|
||||
app.get('/pages', page.getAll)
|
||||
app.get('/pages/urls', page.getUrls)
|
||||
app.get('/pages/:slug', page.getItem)
|
||||
app.get('/page', page.getItem)
|
||||
|
||||
app.get('/images/:slug', image.getItem)
|
||||
|
||||
|
||||
+6
-628
@@ -1,635 +1,13 @@
|
||||
const withCss = require('@zeit/next-css')
|
||||
const withSass = require('@zeit/next-sass')
|
||||
const { range } = require('lodash')
|
||||
|
||||
function createPath(page, map, query, items) {
|
||||
return items.reduce((acc, path) => {
|
||||
return {
|
||||
...acc,
|
||||
[path]: {
|
||||
page,
|
||||
query: query(map(path)),
|
||||
}
|
||||
}
|
||||
}, {})
|
||||
}
|
||||
|
||||
module.exports = withCss(withSass({
|
||||
exportTrailingSlash: true,
|
||||
serverRuntimeConfig: {
|
||||
dbUri: '',
|
||||
// Will only be available on the server side
|
||||
// mySecret: 'secret',
|
||||
// secondSecret: process.env.SECOND_SECRET // Pass through env variables
|
||||
env: {
|
||||
APP_ARTICLES_PAGE_SIZE: 15,
|
||||
},
|
||||
webpack(config) {
|
||||
config.resolve.modules.push(__dirname)
|
||||
return config;
|
||||
},
|
||||
exportPathMap: async (defaultPathMap, { dev }) => {
|
||||
if (dev) {
|
||||
return null
|
||||
}
|
||||
|
||||
const articlesPageSize = 15
|
||||
const articlesLastPage = 8
|
||||
|
||||
return {
|
||||
// ...defaultPathMap,
|
||||
'/': { page: '/', query: { pageSize: articlesPageSize } },
|
||||
'/documents': { page: '/documents' },
|
||||
'/gallery': { page: '/gallery' },
|
||||
'/collective': { page: '/collective' },
|
||||
'/schedule': { page: '/schedule' },
|
||||
|
||||
...createPath(
|
||||
'/articles/[page]',
|
||||
x => x.replace('/articles/', ''),
|
||||
page => ({ page, pageSize: articlesPageSize }),
|
||||
range(1, articlesLastPage + 1).map(x => `/articles/${x}`),
|
||||
),
|
||||
...createPath(
|
||||
'/next',
|
||||
x => x,
|
||||
() => ({}),
|
||||
[
|
||||
'/info/vacancy',
|
||||
'/info/new',
|
||||
'/info/support',
|
||||
'/info/education',
|
||||
'/info/standards',
|
||||
'/info/main',
|
||||
'/info/paid-services',
|
||||
'/info',
|
||||
'/info/tools',
|
||||
'/info/grants',
|
||||
'/info/structure',
|
||||
'/info/finances',
|
||||
'/courses',
|
||||
'/courses/batik',
|
||||
'/courses/ceramics',
|
||||
'/courses/composition',
|
||||
'/courses/costume-composition',
|
||||
'/courses/cg',
|
||||
'/courses/scale-modeling',
|
||||
'/courses/drawing',
|
||||
'/courses/easel-composition',
|
||||
'/courses/felting',
|
||||
'/info/history',
|
||||
'/courses/art-history',
|
||||
'/info/documents',
|
||||
'/info/online-education',
|
||||
'/info/education/listochki',
|
||||
'/info/education/matreshki',
|
||||
'/info/education/perishki',
|
||||
'/info/support/objects',
|
||||
'/info/support/tools',
|
||||
'/info/support/sport',
|
||||
'/info/support/network',
|
||||
'/info/education/painting',
|
||||
'/info/education/art-for-beginners',
|
||||
'/join',
|
||||
'/info/audit',
|
||||
'/summer-school/2017',
|
||||
'/info/health-saving',
|
||||
'/summer-school/2017',
|
||||
'/info/education/painting',
|
||||
'/info/education/art-for-beginners',
|
||||
'/info/education/listochki',
|
||||
'/info/education/matreshki',
|
||||
'/info/education/perishki',
|
||||
'/info/vacancy',
|
||||
'/info/online-education',
|
||||
'/info/documents',
|
||||
'/info/new',
|
||||
'/info/support',
|
||||
'/info/support/objects',
|
||||
'/info/support/tools',
|
||||
'/info/education',
|
||||
'/info/standards',
|
||||
'/info/main',
|
||||
'/info/paid-services',
|
||||
'/join',
|
||||
'/courses',
|
||||
'/info/support/network',
|
||||
'/info',
|
||||
'/info/tools',
|
||||
'/info/support/sport',
|
||||
'/info/grants',
|
||||
'/info/structure',
|
||||
'/info/audit',
|
||||
'/info/finances',
|
||||
'/info/health-saving',
|
||||
'/info/history',
|
||||
'/courses/batik',
|
||||
'/courses/felting',
|
||||
'/courses/art-history',
|
||||
'/courses/ceramics',
|
||||
'/courses/composition',
|
||||
'/courses/costume-composition',
|
||||
'/courses/cg',
|
||||
'/courses/scale-modeling',
|
||||
'/courses/drawing',
|
||||
'/courses/easel-composition',
|
||||
'/courses/listochki',
|
||||
'/courses/matreshki',
|
||||
'/courses/perishki',
|
||||
'/neighbors',
|
||||
'/neighbors/2017',
|
||||
'/neighbors/2017/continuing-the-chronicle',
|
||||
'/neighbors/2017/favorite-view-of-native-place',
|
||||
'/neighbors/2016',
|
||||
'/neighbors/2016/continuing-the-chronicle',
|
||||
'/neighbors/2016/quite-provincial-life',
|
||||
'/neighbors/2016/illustrations-rimsky-korsakov-works',
|
||||
'/neighbors/2017/quite-provincial-life',
|
||||
'/neighbors/2016/favorite-view-of-native-place',
|
||||
'/neighbors/2015',
|
||||
'/neighbors/2015/industrial-landscape',
|
||||
'/neighbors/2015/favorite-view-of-native-place',
|
||||
'/neighbors/2015/continuing-the-chronicle',
|
||||
'/neighbors/2015/these-places-remember-the-war',
|
||||
'/info/corruption',
|
||||
'/domik',
|
||||
'/courses/ladushki',
|
||||
'/info/security',
|
||||
'/neighbors/2018/continuing-the-chronicle',
|
||||
'/neighbors/2018',
|
||||
'/neighbors/2018/favorite-view-of-native-place',
|
||||
'/neighbors/2018/industrial-landscape',
|
||||
'/info/navigator',
|
||||
]
|
||||
),
|
||||
...createPath(
|
||||
'/teacher/[person]',
|
||||
x => x.replace('/teacher/', ''),
|
||||
person => ({ person }),
|
||||
[
|
||||
'/teacher/as-timasheva',
|
||||
'/teacher/va-sarzhin',
|
||||
'/teacher/vv-voronova',
|
||||
'/teacher/ea-burovtseva',
|
||||
'/teacher/ey-tarasova',
|
||||
'/teacher/iv-khramov',
|
||||
'/teacher/in-vturina',
|
||||
'/teacher/ma-khramova',
|
||||
'/teacher/mg-timasheva',
|
||||
'/teacher/my-valkova',
|
||||
'/teacher/nv-andreeva',
|
||||
'/teacher/od-gogoleva',
|
||||
'/teacher/rk-timashev',
|
||||
'/teacher/sa-latipova',
|
||||
],
|
||||
),
|
||||
...createPath(
|
||||
'/article/[article]',
|
||||
x => x.replace('/article/', ''),
|
||||
person => ({ person }),
|
||||
[
|
||||
'/article/2009-ntv',
|
||||
'/article/2010-tv100',
|
||||
'/article/oblastnoi-plener-udalsia-na-slavu',
|
||||
'/article/pervyi-kinopokaz',
|
||||
'/article/30',
|
||||
'/article/kinopokaz',
|
||||
'/article/elka-dlia-malyshei-2015',
|
||||
'/article/vystavka-kukly-korennykh-narodov-leningradskoi-oblasti',
|
||||
'/article/vystavka-kukly-srednei-azii-i-kavkaza',
|
||||
'/article/detskii-sadik',
|
||||
'/article/think-try-create',
|
||||
'/article/konkurs-volshebnaia-kist-na-nekrasova',
|
||||
'/article/master-klass-po-izgotovleniiu-vatnykh-kukol-na-nekrasova',
|
||||
'/article/2015-pridumyvai-probui-tvori',
|
||||
'/article/vystavka-vesna-2015',
|
||||
'/article/exhibition-70',
|
||||
'/article/vesna-2015',
|
||||
'/article/vystavka-letnikh-rabot',
|
||||
'/article/kinopokaz-chukovsky',
|
||||
'/article/kino-domik',
|
||||
'/article/vystavka-v-biblioteke-nekrasova',
|
||||
'/article/konkurs-volshebnaia-kist',
|
||||
'/article/russian-history-competition',
|
||||
'/article/master-klass-pogoleshechnaia-kukla',
|
||||
'/article/2016-pridumyvai-probui-tvori',
|
||||
'/article/prazdnik-v-muzykalnoi-shkole-shlisselburga',
|
||||
'/article/nabor-detei-s-7-mi-do-9-ti-let',
|
||||
'/article/serebro-za-vizitku',
|
||||
'/article/talant-vospityvaetsia-v-trude',
|
||||
'/article/2016-10-kaniculi',
|
||||
'/article/2016-tikhvin',
|
||||
'/article/2016-mi-sosedi',
|
||||
'/article/master-klass-po-kalligrafii',
|
||||
'/article/2016-master-class-calligraphy',
|
||||
'/article/2016-11-kaniculi',
|
||||
'/article/vtoroi-master-klass-po-kalligrafii',
|
||||
'/article/2016-master-class-vatnoe-papie-mashe',
|
||||
'/article/2016-ny-master-class',
|
||||
'/article/2016-master-class-calligraphy-2',
|
||||
'/article/v-nominatsii-sovremennaia-kukla-pobedili-iolochnye-ukrasheniia-shlisselburgskoi-masteritsy',
|
||||
'/article/anons-master-klassa-kukly-voennykh-let',
|
||||
'/article/master-klass-kukly-voennykh-let',
|
||||
'/article/deiateli-kultury-gordost-leningradskoi-oblasti',
|
||||
'/article/gostevoi-dom-shlisselburg',
|
||||
'/article/uchastie-v-konkurse-zvuk-i-forma',
|
||||
'/article/vizit-gubernatora-leningradskoi-oblasti',
|
||||
'/article/anons-konkursa-smotrimvidim',
|
||||
'/article/anons-letnei-shkoly',
|
||||
'/article/master-class-papier-mache-2017',
|
||||
'/article/cats-master-class-2017',
|
||||
'/article/vyborg-announcement-2017',
|
||||
'/article/vyborg-info-2017',
|
||||
'/article/smotrim-vidim-final-announcement-2017',
|
||||
'/article/summer-school-info-2017',
|
||||
'/article/smotrim-vidim-final-2017',
|
||||
'/article/vyborg-2017',
|
||||
'/article/2017-info-new',
|
||||
'/article/preparing-2017',
|
||||
'/article/sarzhin-star',
|
||||
'/article/toropets',
|
||||
'/article/sarzhin-october',
|
||||
'/article/2017-10-kaniculi',
|
||||
'/article/2017-10-workshop',
|
||||
'/article/shlisselshved',
|
||||
'/article/shlisselburg-315',
|
||||
'/article/scholarship-2017',
|
||||
'/article/sarzhin-70',
|
||||
'/article/2017-10-workshop-ceramics',
|
||||
'/article/2017-katavasia',
|
||||
'/article/2017-golden-hands',
|
||||
'/article/2016-liditse',
|
||||
'/article/2017-the-authors-style',
|
||||
'/article/2017-dpi-methods',
|
||||
'/article/2017-oreshek-workshop',
|
||||
'/article/2017-neighbors-vybord-rewarding',
|
||||
'/article/2017-stars',
|
||||
'/article/2017-petrovskaya-aquatoria-trip',
|
||||
'/article/2017-dnt',
|
||||
'/article/silver-pencil-2018',
|
||||
'/article/magic-brush-2018',
|
||||
'/article/blokada-workshop-2018',
|
||||
'/article/best-teacher-2018',
|
||||
'/article/save-nature-competition-2018',
|
||||
'/article/win-day-2018',
|
||||
'/article/site-iii-2018',
|
||||
'/article/israel-2018',
|
||||
'/article/blokada-workshop-2-2018',
|
||||
'/article/plain-air-2018',
|
||||
'/article/graduation-2018',
|
||||
'/article/blokada-workshop-3-2018',
|
||||
'/article/2012-timestamp',
|
||||
'/article/plain-air-june-2018',
|
||||
'/article/berezka-2018',
|
||||
'/article/plain-air-pro-2018',
|
||||
'/article/2018-neighbors-kronshtadt',
|
||||
'/article/vyborg-competition-2018',
|
||||
'/article/norway-2018',
|
||||
'/article/family-album-2018',
|
||||
'/article/2018-neighbors-ceremony',
|
||||
'/article/2018-100',
|
||||
'/article/2018-buduschee-moey-strany',
|
||||
'/article/2019-nv-andreeva',
|
||||
'/article/2019-blokada-workshop',
|
||||
'/article/2018-culture-star',
|
||||
'/article/2018-guests-from-germany',
|
||||
'/article/2018-grants',
|
||||
'/article/2018-inclusive-education',
|
||||
'/article/2018-neighbors-announcement',
|
||||
'/article/2019-fortuna',
|
||||
'/article/2019-orchestra',
|
||||
'/article/2019-magic-brush',
|
||||
'/article/2019-silver-pencil',
|
||||
'/article/2019-spring-subbotnik',
|
||||
'/article/2019-win500',
|
||||
'/article/2019-korushka',
|
||||
'/article/2019-pleinair',
|
||||
'/article/2019-kotiki',
|
||||
'/article/2019-serafima',
|
||||
'/article/2019-competition-authors-style',
|
||||
'/article/2019-survey',
|
||||
'/article/2019-navigator',
|
||||
'/article/2019-unikum',
|
||||
],
|
||||
),
|
||||
...createPath(
|
||||
'/album/[album]',
|
||||
x => x.replace('/album/', ''),
|
||||
album => ({ album }),
|
||||
[
|
||||
'/album/2012-tekhnika-mokrogo-valianiia',
|
||||
'/album/2013-valianie-zverushki',
|
||||
'/album/2013-shlisselburg',
|
||||
'/album/2013-natiurmort',
|
||||
'/album/2015-kukly-valianie',
|
||||
'/album/2014-kollazh',
|
||||
'/album/2014-shlisselburg',
|
||||
'/album/2014-elochnye-domiki',
|
||||
'/album/2014-elochnye-igrushki',
|
||||
'/album/2014-zhivopis-narody-severa',
|
||||
'/album/2015-maketirovanie-doma-peterburga',
|
||||
'/album/2015-zhivopis',
|
||||
'/album/2015-maketirovanie',
|
||||
'/album/2015-podvodnyi-mir-stankovaia-kompozitsiia',
|
||||
'/album/2015-risunok',
|
||||
'/album/2015-skazki',
|
||||
'/album/2015-stankovaia-kompozitsiia',
|
||||
'/album/2015-tsvety-stankovaia-kompozitsiia',
|
||||
'/album/2015-graviura',
|
||||
'/album/2015-guash',
|
||||
'/album/2015-shlisselburg',
|
||||
'/album/2015-dpk-portret-v-tekhnike-applikatsiia',
|
||||
'/album/2015-nominatsiia-navstrechu-pobede',
|
||||
'/album/2015-domiki',
|
||||
'/album/2015-skulptury-na-temu-70-let-pobedy',
|
||||
'/album/2015-history-competition',
|
||||
'/album/2015-rozhdestvenskaia-skazka',
|
||||
'/album/2016-konkurs-zimnie-zabavy',
|
||||
'/album/2016-konkurs-na-kryliakh-babochek',
|
||||
'/album/2016-konkurs-narodnye-motivy',
|
||||
'/album/around-the-world',
|
||||
'/album/comod',
|
||||
'/album/leto-domovenok',
|
||||
'/album/2016-tikhvin-mi-sosedi',
|
||||
'/album/2017-konkurs-budushchee-moei-strany',
|
||||
'/album/2017-konkurs-puteshestvie-k-dinozavram',
|
||||
'/album/2017-konkurs-eto-mamin-den',
|
||||
'/album/2017-konkurs-forma-i-zvuk',
|
||||
'/album/pleinair-competition-2017',
|
||||
'/album/ceramics-2017',
|
||||
'/album/vyborg-makets-2017',
|
||||
'/album/ceramics-march-2018',
|
||||
'/album/ceramics-june-2018',
|
||||
'/album/batik-june-2018',
|
||||
'/album/village-pictures-june-2018',
|
||||
'/album/fortress-june-2018',
|
||||
'/album/baloons-june-2018',
|
||||
'/album/drawing-jule-2018',
|
||||
'/album/drawing-june-2018',
|
||||
'/album/painting-june-2018',
|
||||
],
|
||||
),
|
||||
...createPath(
|
||||
'/document/[document]',
|
||||
x => x.replace('/document/', ''),
|
||||
document => ({ document }),
|
||||
[
|
||||
'/document/documents-2017-2018-kalendarnyi-grafik-2017-2018-pdf',
|
||||
'/document/documents-arkhiv-obrazovatelnaia-litsenziia-2013-pdf',
|
||||
'/document/documents-arkhiv-plan-vnutrishkolnogo-kontrolia-2012-pdf',
|
||||
'/document/documents-arkhiv-polozhenie-o-vnutrishkolnom-kontrole-2012-pdf',
|
||||
'/document/documents-arkhiv-polozhenie-o-pedagogicheskom-sovete-pdf',
|
||||
'/document/documents-arkhiv-polozhenie-o-prieme-perevode-otchislenii-pdf',
|
||||
'/document/documents-arkhiv-polozhenie-o-propusknom-rezhime-2015-pdf',
|
||||
'/document/documents-arkhiv-pravila-i-polozhenie-o-prieme-v-shkolu-pdf',
|
||||
'/document/documents-arkhiv-ustav-2013-pdf',
|
||||
'/document/documents-dokumenty-dlia-postupleniia-dogovor-o-pozhertvovanii-pdf',
|
||||
'/document/documents-dokumenty-dlia-postupleniia-dogovor-o-sotrudnichestve-pdf',
|
||||
'/document/documents-dokumenty-dlia-postupleniia-zaiavlenie-roditelei-pdf',
|
||||
'/document/documents-instruktsii-instruktsiia-po-organizatsii-okhrany-zhizni-i-zdorovia-detei-pdf',
|
||||
'/document/documents-instruktsii-instruktsiia-po-okhrane-zhizni-i-zdorovia-detei-pdf',
|
||||
'/document/documents-instruktsii-plan-vnutrishkolnogo-kontrolia-2016-pdf',
|
||||
'/document/documents-instruktsii-pravila-vnutrennego-trudovogo-rasporiadka-pdf',
|
||||
'/document/documents-materialno-tekhnicheskoe-obespechenie-i-osnashchennost-obrazovatelnogo-protsessa-vnutrishkolnyi-metodicheskii-bibliotechnyi-fond-pdf',
|
||||
'/document/documents-materialno-tekhnicheskoe-obespechenie-i-osnashchennost-obrazovatelnogo-protsessa-dogovor-na-meditsinskoe-obsluzhivanie-pdf',
|
||||
'/document/documents-materialno-tekhnicheskoe-obespechenie-i-osnashchennost-obrazovatelnogo-protsessa-dogovor-na-okazanie-uslug-po-organizatsii-pitaniia-pdf',
|
||||
'/document/documents-materialno-tekhnicheskoe-obespechenie-i-osnashchennost-obrazovatelnogo-protsessa-dogovor-na-okazanie-uslug-sviazi-pdf',
|
||||
'/document/documents-materialno-tekhnicheskoe-obespechenie-i-osnashchennost-obrazovatelnogo-protsessa-materialno-tekhnicheskoe-obespecheninie-obrazovatelnogo-protsessa-pdf',
|
||||
'/document/documents-obrazovanie-dopolnitelnaia-obshcherazvivaiushchaia-programma-khudozhestvennoi-napravlennosti-izobrazitelnoe-iskusstvo-dlia-nachinaiushchikh-pdf',
|
||||
'/document/documents-obrazovanie-dopolnitelnaia-obshcherazvivaiushchaia-programma-khudozhestvennoi-napravlennosti-dlia-obuchaiushchikhsia-podgotovitelnykh-klassov-v-dkhsh-listochki-pdf',
|
||||
'/document/documents-obrazovanie-dopolnitelnaia-obshcherazvivaiushchaia-programma-khudozhestvennoi-napravlennosti-dlia-obuchaiushchikhsia-podgotovitelnykh-klassov-v-dkhsh-matreshki-pdf',
|
||||
'/document/documents-obrazovanie-dopolnitelnaia-obshcherazvivaiushchaia-programma-khudozhestvennoi-napravlennosti-dlia-obuchaiushchikhsia-podgotovitelnykh-klassov-v-dkhsh-peryshki-pdf',
|
||||
'/document/documents-obrazovanie-dopolnitelnaia-predprofessionalnaia-obshcheobrazovatelnaia-programma-v-oblasti-izobrazitelnogo-iskusstva-zhivopis-pdf',
|
||||
'/document/documents-obrazovanie-dpop-zhivopis-pdf',
|
||||
'/document/documents-obrazovanie-kalendarnyi-uchebnyi-grafik-pdf',
|
||||
'/document/documents-obrazovanie-opisanie-obrazovatelnoi-programmy-izobrazitelnoe-iskusstvo-dlia-nachinaiushchikh-pdf',
|
||||
'/document/documents-obrazovanie-opisanie-obshcheobrazovatelnoi-programmy-v-oblasti-izobrazitelnogo-iskusstva-zhivopis-pdf',
|
||||
'/document/documents-obrazovanie-polozhenie-o-komplektovanii-i-napolniaemosti-grupp-pdf',
|
||||
'/document/documents-obrazovanie-polozhenie-o-poriadke-obucheniia-po-individualnomu-uchebnomu-planu-pdf',
|
||||
'/document/documents-obrazovanie-polozhenie-o-iazyke-obrazovaniia-v-mbudo-shlisselburgskaia-dkhsh-pdf',
|
||||
'/document/documents-obrazovanie-programma-obucheniia-2017-pdf',
|
||||
'/document/documents-obrazovanie-uchebnyi-plan-po-izobrazitelnomu-iskusstvu-pdf',
|
||||
'/document/documents-obrazovanie-uchebnyi-plan-po-dopolnitelnoi-obshcherazvivaiushchei-podgotovitelnoi-programme-po-izobrazitelnomu-iskusstvu-pdf',
|
||||
'/document/documents-obrazovanie-uchebnyi-plan-po-dopolnitelnoi-predprofessionalnoi-obshcheobrazovatelnoi-programme-v-oblasti-izobrazitelnogo-iskusstva-zhivopis-pdf',
|
||||
'/document/documents-osnovnye-dokumenty-egriul-pdf',
|
||||
'/document/documents-osnovnye-dokumenty-inn-pdf',
|
||||
'/document/documents-osnovnye-dokumenty-kopiia-resheniia-o-naznachenii-rukovoditelia-pdf',
|
||||
'/document/documents-osnovnye-dokumenty-obrazovatelnaia-litsenziia-2015-pdf',
|
||||
'/document/documents-osnovnye-dokumenty-polozhenie-o-vnutrishkolnom-kontrole-2017-pdf',
|
||||
'/document/documents-osnovnye-dokumenty-polozhenie-o-dobrovolnom-pozhertvovanii-pdf',
|
||||
'/document/documents-osnovnye-dokumenty-polozhenie-o-kodekse-professionalnoi-etiki-pedagogicheskikh-rabotnikov-pdf',
|
||||
'/document/documents-osnovnye-dokumenty-polozhenie-o-pedagogicheskom-sovete-pdf',
|
||||
'/document/documents-osnovnye-dokumenty-polozhenie-o-poriadke-vydachi-dokumenta-ob-obuchenii-pdf',
|
||||
'/document/documents-osnovnye-dokumenty-polozhenie-o-pravilakh-vnutrennego-rasporiadka-obuchaiushchikhsia-pdf',
|
||||
'/document/documents-osnovnye-dokumenty-polozhenie-o-prieme-v-shkolu-pdf',
|
||||
'/document/documents-osnovnye-dokumenty-polozhenie-o-propusknom-rezhime-pdf',
|
||||
'/document/documents-osnovnye-dokumenty-polozhenie-o-sovete-shkoly-2017-pdf',
|
||||
'/document/documents-osnovnye-dokumenty-polozhenie-o-formakh-periodichnosti-i-poriadke-tekushchego-kontrolia-uspevaemosti-promezhutochnoi-attestatsii-obuchaiaiushchikhsia-pdf',
|
||||
'/document/documents-osnovnye-dokumenty-polozhenie-ob-appeliatsionnoi-komissii-pdf',
|
||||
'/document/documents-osnovnye-dokumenty-polozhenie-ob-itogovoi-attestatsii-pdf',
|
||||
'/document/documents-osnovnye-dokumenty-polozhenie-ob-obshchem-sobranii-rabotnikov-pdf',
|
||||
'/document/documents-osnovnye-dokumenty-polozhenie-ob-usloviiakh-provedeniia-individualnogo-otbora-dlia-postupaiushchikh-s-ogranichennymi-vozmozhnostiami-zdorovia-pdf',
|
||||
'/document/documents-osnovnye-dokumenty-polozhenie-po-promezhutochnoi-attestatsii-pdf',
|
||||
'/document/documents-osnovnye-dokumenty-postanovlenie-o-sozdanii-munitsipalnogo-obrazovatelnogo-uchrezhdeniia-kultury-detskaia-khudozhestvennaia-shkola-pdf',
|
||||
'/document/documents-osnovnye-dokumenty-programma-razvitiia-na-2017-2020-gg-pdf',
|
||||
'/document/documents-osnovnye-dokumenty-rezhim-zaniatii-obuchaiushchikhsia-pdf',
|
||||
'/document/documents-osnovnye-dokumenty-reshenie-o-sozdanii-shkoly-pdf',
|
||||
'/document/documents-osnovnye-dokumenty-svidetelstvo-na-pomeshchenie-pdf',
|
||||
'/document/documents-osnovnye-dokumenty-ustav-2015-pdf',
|
||||
'/document/documents-plany-fkhd-munitsipalnoe-zadanie-na-2017-god-i-na-planovyi-period-2018-i-2019-godov-pdf',
|
||||
'/document/documents-plany-fkhd-otchet-o-vypolnenii-munitsipalnogo-zadaniia-2016-god-pdf',
|
||||
'/document/documents-plany-fkhd-plan-finansovoi-khoziaistvennoi-deiatelnosti-na-2016-god-pdf',
|
||||
'/document/documents-plany-fkhd-plan-finansovoi-khoziaistvennoi-deiatelnosti-na-2017-god-pdf',
|
||||
'/document/documents-platnye-obrazovatelnye-uslugi-dogovor-ob-okazanii-platnykh-obrazovatelnykh-uslug-pdf',
|
||||
'/document/documents-platnye-obrazovatelnye-uslugi-zaiavlenie-na-platnye-obrazovatelnye-uslugi-pdf',
|
||||
'/document/documents-platnye-obrazovatelnye-uslugi-polozhenie-o-poriadke-predostavleniia-platnykh-obrazovatelnykh-uslug-pdf',
|
||||
'/document/documents-platnye-obrazovatelnye-uslugi-prikaz-ob-ustanovlenii-razmera-platnykh-obrazovatelnykh-uslug-pdf',
|
||||
'/document/documents-prochee-2016-zaiavka-na-uchastie-v-44-mvkhpd-v-liditse-pdf',
|
||||
'/document/documents-prochee-2016-rezultat-samoobsledovaniia-pdf',
|
||||
'/document/documents-prochee-dostizheniia-obuchaiushchikhsia-v-2015-2016-godu-pdf',
|
||||
'/document/documents-prochee-litsenziia-spbimi-pdf',
|
||||
'/document/documents-prochee-otsenka-kachestva-uslug-uchrezhdeniia-kultury-pdf',
|
||||
'/document/documents-prochee-polozhenie-smotrim-vidim-pdf',
|
||||
'/document/documents-prochee-rasporiazhenie-o-prisvoenii-stipendii-2017-2018-pdf',
|
||||
'/document/documents-prochee-rasporiazhenie-ot-30-05-2017-pdf',
|
||||
'/document/documents-prochee-spisok-materialov-dlia-zaniatiia-v-khudozhestvennoi-shkole-pdf',
|
||||
'/document/documents-samoobsledovanie-deiatelnosti-otchet-o-rezultatakh-samoobsledovaniia-01-04-2016-pdf',
|
||||
'/document/documents-samoobsledovanie-deiatelnosti-otchet-o-rezultatakh-samoobsledovaniia-01-04-2017-pdf',
|
||||
'/document/documents-tekushchii-kontrol-akt-proverki-komiteta-obshchego-i-professionalnogo-obrazovaniia-leningradskoi-oblasti-2017-pdf',
|
||||
'/document/documents-uchebnye-programmy-izobrazitelnoe-iskusstvo-dlia-nachinaiushchikh-pdf',
|
||||
'/document/documents-uchebnye-programmy-programma-po-predmetu-skulptura-pdf',
|
||||
'/document/documents-uchebnye-programmy-progrmma-po-predmetu-plener-pdf',
|
||||
'/document/documents-uchebnye-programmy-uchebnaia-programma-zhivopis-pdf',
|
||||
'/document/documents-uchebnye-programmy-uchebnaia-programma-istoriia-iskusstva-pdf',
|
||||
'/document/documents-uchebnye-programmy-uchebnaia-programma-prikladnaia-kompozitsiia-pdf',
|
||||
'/document/documents-uchebnye-programmy-uchebnaia-programma-risunok-pdf',
|
||||
'/document/documents-uchebnye-programmy-uchebnaia-programma-stankovaia-kompozitsiia-pdf',
|
||||
'/document/documents-finansovo-khoziaistvennaia-deiatelnost-balans-gosudarstvennogo-(munitsipalnogo)-uchrezhdeniia-pdf',
|
||||
'/document/documents-finansovo-khoziaistvennaia-deiatelnost-otchet-o-finansovykh-rezultatakh-deiatelnosti-uchrezhdeniia-pdf',
|
||||
'/document/documents-finansovo-khoziaistvennaia-deiatelnost-otchet-ob-ispolnenii-uchrezhdeniem-plana-ego-finansovo-khoziaistvennoi-deiatelnosti-forma-737-kfo-4-pdf',
|
||||
'/document/documents-finansovo-khoziaistvennaia-deiatelnost-otchet-ob-ispolnenii-uchrezhdeniem-plana-ego-finansovo-khoziaistvennoi-deiatelnosti-forma-737-kfo-5-pdf',
|
||||
'/document/documents-finansovo-khoziaistvennaia-deiatelnost-otchet-ob-ispolnenii-uchrezhdeniem-plana-ego-finansovo-khoziaistvennoi-deiatelnosti-pdf',
|
||||
'/document/pages-finansovo-khoziaistvennaia-deiatelnost-balans-pdf',
|
||||
'/document/370f8cc297f40d170470e8768ddd227c',
|
||||
'/document/792bf2823b7840318b02f7d2758af788',
|
||||
'/document/f574413240ff8ff35091f023976688ee',
|
||||
'/document/758260df3b7fa615e2fc8a3d2ed9e34c',
|
||||
'/document/00c90a531da459ab9f10a3d52bac233f',
|
||||
'/document/2eae32c837bbbd84f403dd7628354b1d',
|
||||
'/document/fa42795ab1879d009961b5bf69e8c597',
|
||||
'/document/8f74abfd61354daf8d73e4000b525fdd',
|
||||
'/document/fe14659e16c98005f4c5168ee3cccc9a',
|
||||
'/document/98564c3f7c9ce1e5c5f1aa1fe302eaf6',
|
||||
'/document/6d7359437624b3dd1484d82be66f1ea0',
|
||||
'/document/4e4ed5431035f97da26eb6b17d88658e',
|
||||
'/document/dfef1cc07b4317d2d380efc4259dc363',
|
||||
'/document/8c19548aa39c40a8a2abc4bca20714ca',
|
||||
'/document/caef7508b14605982d483a5f05756714',
|
||||
'/document/9f6683f63172a794fd3c6031f781d348',
|
||||
'/document/acaa47304de042433e26e5eabbbfdeec',
|
||||
'/document/e094b1f74e8d381b77b510d9f040a616',
|
||||
'/document/b19092ace94edcf2e7ee0274207b8aa9',
|
||||
'/document/47883f1e226c48c42e1cb7a9e811bec8',
|
||||
'/document/ee54f828803e91c7f385b621143f0daf',
|
||||
'/document/9149c0d182401643c6307ac9ffb1dc65',
|
||||
'/document/7f229ba5f7882a8a2684289204a8308e',
|
||||
'/document/37277ec7ddc90a316effef4a3a6ec1c3',
|
||||
'/document/d50a7953d5a65f4155f7035740594a47',
|
||||
'/document/ae3d2bc577bfd45f1cbc420f8691de2e',
|
||||
'/document/b54ad2943689658cccd20c215724bc7d',
|
||||
'/document/918b27593c43576dfd85b817005f9925',
|
||||
'/document/77144e7b8eb675d0189c63be1818d964',
|
||||
'/document/20f2fafe77196edb54857fe0b98438a6',
|
||||
'/document/e0cdee9ba8a56919f92af7f0363e713f',
|
||||
'/document/e3e2da7bdd4cdb4fb05a7d72a1c5aa24',
|
||||
'/document/5883367e713100cfdfa074fbab675907',
|
||||
'/document/0415c9a50eb0b56651bbcf3d7388a373',
|
||||
'/document/aa69b76d675e1e30661365deb2e5deef',
|
||||
'/document/4e35368e42c1840e89c3a3714d3f323b',
|
||||
'/document/5bd563e2b1b8e0cb20ee2438a5d4888a',
|
||||
'/document/b19069cc9b3c5be5a92487f9d3385064',
|
||||
'/document/53f8111c3882521453d889aa84dedea3',
|
||||
'/document/58e4a7445b19ae0dbe1ee6313cbcee50',
|
||||
'/document/76a8fc2870f1254a52e80712115ea448',
|
||||
'/document/dab46182c1c119210b3a8ba4a3079d15',
|
||||
'/document/52101c7e4bb3bbdc315f93dff8b826ca',
|
||||
'/document/5a677e08537853a1f4d11a7ae492f8b6',
|
||||
'/document/2dc1c2e7cfa996c13fb90045c5e4b5fb',
|
||||
'/document/952e1ed8ec2879eb4d2e300c1b50d890',
|
||||
'/document/0d20b54c2023563ec0cdff648ed8070d',
|
||||
'/document/82e9e339678a9385ab44897837a0e7f6',
|
||||
'/document/ae64123551407d5c325f75d83f58a338',
|
||||
'/document/bd1ace5ed47ee0958254f6a9732482cc',
|
||||
'/document/534566e01344b0d1dfec8e3cb0dfc8a9',
|
||||
'/document/739bd6b500c6bebe742df3d70a0c1fdc',
|
||||
'/document/00a6c04a383bea80a619d4a86bb1b46f',
|
||||
'/document/5c9708d3d3c9d6141ed7865a8a3d9566',
|
||||
'/document/6fec7aa79b5edef99dc5498d8ddc9b28',
|
||||
'/document/2f4ab4732107b2ce84e2dd9327d2788f',
|
||||
'/document/d91de578e0a3b5d0878857bebf859124',
|
||||
'/document/a056376a142ac924485ff6f222ab116d',
|
||||
'/document/ded3933486acbc63ee0897d768a0af5a',
|
||||
'/document/f3a21a6b0dc669034542c575dc4a9cb0',
|
||||
'/document/f08cd96300031e83a55699f257046eb3',
|
||||
'/document/77b23264aa63ebc2f60811fe46595140',
|
||||
'/document/58269cb439dd9860b277a772a5651597',
|
||||
'/document/e87b1ce25b43a4f4613bf35aa1ce17ef',
|
||||
'/document/2a17275330cfc5933447fa5631a1a137',
|
||||
'/document/e0726255b3b1275c468432e6825acc8c',
|
||||
'/document/0d8ba20dc95b0b8cecde26f83821ac60',
|
||||
'/document/cc02b4688caa24f55da4a36d54d89712',
|
||||
'/document/3df73e48c1bc1acf4725e158a7abbea2',
|
||||
'/document/c27d39f66acd8c1e50c66ddc5d0a2d39',
|
||||
'/document/efd17fc5298d12a4b4a73238e01bc4c1',
|
||||
'/document/19e094faea42621de8ea362493c6149a',
|
||||
'/document/869d3c46dc48c31870ff169e1d53ba0f',
|
||||
'/document/be8201b8f5b0d995faa851c8dee9bb30',
|
||||
'/document/9e79ef49c9aa132f1b6be66ade0e55ff',
|
||||
'/document/198f53b9de3c8123b0977d9350c26ace',
|
||||
'/document/f16c8bc8830d6d5c939fcb3dc3e9dfc8',
|
||||
'/document/60933dd039b87c2ce5b3f637ec791f71',
|
||||
'/document/1c05245b4e5889bc0f3cc6e7ee3a022b',
|
||||
'/document/fb589fa77a5e78a11e5aa90f27fdb10a',
|
||||
'/document/631962a3257d1196f281f568d780d98f',
|
||||
'/document/e8877efd3f9234997677b0595b0aaa22',
|
||||
'/document/4fe9c744e0b1b9de8dec11db5d6ab29f',
|
||||
'/document/85280b9f3f951c06284ab7fe77a595b6',
|
||||
'/document/76607ea30bd2a7d86710781b6b9fddd4',
|
||||
'/document/ec40bc1ed9ce38d563c2bece509b5021',
|
||||
'/document/074b2b248efc55ae7fe9d157891c59e9',
|
||||
'/document/1d038d40939be8999fe585f71579f09d',
|
||||
'/document/8f1764396b0a6c1a0a32235ad4cd69eb',
|
||||
'/document/4d6524f6c56d7cbeaee699c8b5e37c1b',
|
||||
'/document/c2ea674b1a3069369b1829e568891b05',
|
||||
'/document/6c1fb8a2428b7b95ca103363f1273c57',
|
||||
'/document/e7dae8347ac64981377932e4a93f1237',
|
||||
'/document/10098b1edb8a242253cdc0636106b880',
|
||||
'/document/deba55994dd9dc1bd304c360656e3843',
|
||||
'/document/976dec5025c210b879192929a40b6b27',
|
||||
'/document/1d48ee849ddea9406a423e4b1e1a7405',
|
||||
'/document/cc845874fd3b183b0cd17e7138075028',
|
||||
'/document/81c9a9d965a12ceaf3564128bffd37ad',
|
||||
'/document/e1720a6b5792a81788f10865ef6ecc79',
|
||||
'/document/0f0b7ef81ba0d0a2af96a67322110751',
|
||||
'/document/ba581ef075ea68be80f750ac467e5baf',
|
||||
'/document/3c9062a9dd236b9d533160c0058c8648',
|
||||
'/document/27958a0d3dd1e22e7b2f7c68ca753fb3',
|
||||
'/document/3663f97b6151720d4749574dc9d1e8a4',
|
||||
'/document/2d21b714a1ba64c24289e2e22d080202',
|
||||
'/document/7ebc6f2cae58d6505143a20da047dd80',
|
||||
'/document/1d67ff95477334666d8ae6451f1a32e2',
|
||||
'/document/c2524a36ba4f9885dcd2abcb1fc00afd',
|
||||
'/document/c49ef7b1944a96a8b2552aa7fdb60d1b',
|
||||
'/document/d2b40e5804363a0f326f4d14ad9e0b73',
|
||||
'/document/3149e573fa3a5b680662a4db84078044',
|
||||
'/document/c7ccacb1e86467f1250084280e16a58f',
|
||||
'/document/9b996ba28a688d2b2834b202e14ff317',
|
||||
'/document/8ddbabaf875dfc1652ed327d9760b6cf',
|
||||
'/document/4da000c1bbca5231c9768aaeccdffe1a',
|
||||
'/document/c44153837b872ba80f5d94e7d3641114',
|
||||
'/document/d99da3c6e7962195f6ae5ce31759d076',
|
||||
'/document/6025a889bd12cec858d218f68686b916',
|
||||
'/document/2b2672d859944f1c1b3a63b26ad693ab',
|
||||
'/document/1a3234642a9bf0493c75511eb3bf98c5',
|
||||
'/document/554c91d0c84c693f00b8666534f198d1',
|
||||
'/document/a9bf213af314b8258d70e50ab0a5a3f9',
|
||||
'/document/7bc0d8238189fd0497d6faf51c1ec6ce',
|
||||
'/document/27b858d66f1dd403504139389f1c985f',
|
||||
'/document/2f9873564859bf38c24c2735d3dfc537',
|
||||
'/document/40256172e2be27799361b3980c39737b',
|
||||
'/document/c08980a17eaffa33816aa0b9f52d35da',
|
||||
'/document/26f7783a944186eed230ac234b999da6',
|
||||
'/document/8b1abc982beae70ac2885856aeaef116',
|
||||
'/document/d063d09eb6f2d1d765ab904cb211ff61',
|
||||
'/document/36988b164efadc1348c81916c30076b2',
|
||||
'/document/765798adfe9b6c75f72c20c716705b82',
|
||||
'/document/9a0d71c2d8aa33273b9c631af2b47eb0',
|
||||
'/document/1b8dc4f624b2db9c37097df6011948ca',
|
||||
'/document/8d4ccb007257e11d7ca7c957d2fa715c',
|
||||
'/document/7c1fcbed5fa818d1256a33c628eb6695',
|
||||
'/document/94d1cb5860ec81e00e9fdf24af847a6b',
|
||||
'/document/808a5a90dda72cc3411ca9c1942f0889',
|
||||
'/document/b5ed5defd7154073dd44ed6f8cc4c51d',
|
||||
'/document/65e8b74faa3d2839f08255f8e1835d8e',
|
||||
'/document/f3af7921743fc47718ca39716fdc32d5',
|
||||
'/document/3311e9b7d4e57893b94807c3acbde279',
|
||||
'/document/4ec0139e3466527f71a102e26697b344',
|
||||
'/document/491c8b0ea8032e4fe40e735711258277',
|
||||
'/document/50d171c70356995b921c52568f1cf64e',
|
||||
'/document/033e121e5bc2b487353f512c0258ed1f',
|
||||
'/document/18831d6d910b64c1a7aaa409d694607c',
|
||||
'/document/bee4ca5c3a191bd7c43bb7098259bfcb',
|
||||
'/document/67e0ecd5b41e3b8b18b6d8e809b34f2d',
|
||||
'/document/ffdd72718d2f9d6f824e0304fb4ed0e8',
|
||||
'/document/49a03e53293d4e5be6e16b20fe78f107',
|
||||
'/document/5282789e6ee9ec37b2322abc4011aa80',
|
||||
'/document/e07f6b95ece80ed82977b096156f4ba8',
|
||||
'/document/7fdf9aa60d503f2f01f89a8b19b0c770',
|
||||
'/document/0053224c128c26593816041cfd923fcf',
|
||||
'/document/c150b448136a61c9f30bbc5372a246d1',
|
||||
'/document/40f2efd755b816586ea6fc4459159edf',
|
||||
'/document/d8afbafcf061f1f28cea58f2c2271c68',
|
||||
'/document/966fda6686c99a28bb1792730ea2057f',
|
||||
'/document/7c4f6647a6e5e4b5175eb5ecae971320',
|
||||
'/document/38b8b5be9a2ed9def3a4c80f98a80482',
|
||||
'/document/e33c22584756e7bb9ee0cd84f7899f4b',
|
||||
'/document/176559736c92b222ae27d0f54229dbcc',
|
||||
]
|
||||
),
|
||||
}
|
||||
}
|
||||
}))
|
||||
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"version": 2,
|
||||
"name": "hudozka",
|
||||
"builds": [
|
||||
{
|
||||
"src": "dist/**",
|
||||
"use": "@now/static"
|
||||
}
|
||||
],
|
||||
"routes": [
|
||||
{
|
||||
"src": "/(.*)",
|
||||
"dest": "dist/$1"
|
||||
}
|
||||
]
|
||||
}
|
||||
Generated
+2546
-9508
File diff suppressed because it is too large.
Load diff
+7
-45
@@ -3,12 +3,11 @@
|
||||
"private": true,
|
||||
"version": "6.0.0",
|
||||
"description": "",
|
||||
"main": "src/bin/www.js",
|
||||
"scripts": {
|
||||
"start": "NODE_ENV=production node src/server.js",
|
||||
"dev": "ts-node --project server.tsconfig.json src/server.ts",
|
||||
"next-dev": "next dev",
|
||||
"build": "next build && next export -o dist && npm run sitemap && npm run feed",
|
||||
"start": "next dev",
|
||||
"build": "npm run next-build && npm run export && npm run sitemap && npm run feed",
|
||||
"next-build": "next build",
|
||||
"export": "next export -o dist",
|
||||
"sitemap": "node scripts/sitemap.js",
|
||||
"feed": "node scripts/feed.js",
|
||||
"test": "mocha --compilers js:babel-register"
|
||||
@@ -22,56 +21,21 @@
|
||||
"dependencies": {
|
||||
"axios": "^0.19.0",
|
||||
"classnames": "^2.2.6",
|
||||
"co": "^4.4.0",
|
||||
"ejson": "^2.2.0",
|
||||
"handlebars": "^4.5.3",
|
||||
"immutable": "^3.8.2",
|
||||
"instagram-node": "^0.5.1",
|
||||
"koa": "^2.11.0",
|
||||
"koa-route": "^3.1.0",
|
||||
"lodash": "^4.17.15",
|
||||
"markdown": "^0.5.0",
|
||||
"moment": "^2.24.0",
|
||||
"mongodb": "^2.1.14",
|
||||
"mz": "^2.7.0",
|
||||
"next": "^9.1.4",
|
||||
"next": "^9.2.2-canary.20",
|
||||
"react": "^16.12.0",
|
||||
"react-dom": "^16.12.0",
|
||||
"react-redux": "^4.4.10",
|
||||
"react-router": "^4.3.1",
|
||||
"react-router-redux": "^4.0.8",
|
||||
"redux": "^3.7.2",
|
||||
"redux-thunk": "^2.3.0",
|
||||
"request-promise": "^2.0.1",
|
||||
"sitemap": "^1.5.0",
|
||||
"thunkify": "^2.1.2",
|
||||
"use-media": "^1.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.7.4",
|
||||
"@babel/core": "^7.7.4",
|
||||
"@babel/node": "^7.7.4",
|
||||
"@babel/plugin-proposal-class-properties": "^7.7.4",
|
||||
"@babel/plugin-proposal-object-rest-spread": "^7.7.4",
|
||||
"@babel/polyfill": "^7.7.0",
|
||||
"@babel/preset-env": "^7.7.4",
|
||||
"@babel/preset-typescript": "^7.7.4",
|
||||
"@babel/register": "^7.7.4",
|
||||
"@types/classnames": "^2.2.9",
|
||||
"@types/koa": "^2.0.52",
|
||||
"@types/koa-route": "^3.2.4",
|
||||
"@types/mongodb": "^3.3.11",
|
||||
"@types/lodash": "^4.14.149",
|
||||
"@types/node": "^12.12.12",
|
||||
"@types/react": "^16.9.12",
|
||||
"@zeit/next-css": "^1.0.1",
|
||||
"@zeit/next-sass": "^1.0.1",
|
||||
"autoprefixer": "^6.3.6",
|
||||
"babel-plugin-transform-class-properties": "^6.24.1",
|
||||
"babel-plugin-transform-react-jsx": "^6.23.0",
|
||||
"babel-plugin-transform-regenerator": "^6.26.0",
|
||||
"babel-preset-env": "^1.7.0",
|
||||
"babel-register": "^6.26.0",
|
||||
"cssnano": "^4.1.10",
|
||||
"eslint": "^4.18.2",
|
||||
"eslint-config-standard": "^6.2.1",
|
||||
"eslint-plugin-promise": "^3.8.0",
|
||||
@@ -81,8 +45,6 @@
|
||||
"mocha": "^6.2.2",
|
||||
"node-sass": "^4.13.0",
|
||||
"should": "^8.2.2",
|
||||
"ts-node": "^8.5.2",
|
||||
"typescript": "^3.7.2",
|
||||
"webpack": "^4.41.2"
|
||||
"typescript": "^3.7.5"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
import Head from 'next/head'
|
||||
import { App } from 'src/components/App'
|
||||
import { tail } from 'lodash'
|
||||
import { Page } from 'src/components/Page'
|
||||
import menuModel from 'src/models/menu'
|
||||
import { buildMenu } from 'src/lib/menu'
|
||||
import { Meta } from 'src/components/Meta'
|
||||
import { meta } from 'src/lib/meta'
|
||||
import { createApiUrl, requestGet, wrapInitialProps, IResponseItems } from 'src/next-lib'
|
||||
|
||||
function array<T>(value: T | T[]) {
|
||||
return Array.isArray(value)
|
||||
? value
|
||||
: [value]
|
||||
}
|
||||
|
||||
const Index = props => (
|
||||
<App
|
||||
menu={buildMenu(props.pageUrl, menuModel)}
|
||||
showAuthor={true}
|
||||
menuPadding={true}
|
||||
layout={'thin'}
|
||||
>
|
||||
<Head>
|
||||
<title>{props.title}</title>
|
||||
{/* <Meta meta={props.meta} /> */}
|
||||
</Head>
|
||||
|
||||
<Page
|
||||
showSocialShare={true}
|
||||
>
|
||||
{props.content}
|
||||
</Page>
|
||||
</App>
|
||||
)
|
||||
|
||||
export const unstable_getStaticProps = async (ctx: any) => {
|
||||
let slug = null
|
||||
if (ctx.query) {
|
||||
slug = '/' + array(ctx.query.slug).join('/')
|
||||
} else {
|
||||
slug = '/' + array(ctx.params.slug).join('/')
|
||||
}
|
||||
const page = await requestGet(createApiUrl(`/api/page?page=${slug}`), null)
|
||||
if (!page) {
|
||||
throw new Error(`Not found: ${slug}`)
|
||||
}
|
||||
const image = page.preview ? page.preview.artifacts.fb : {}
|
||||
|
||||
return {
|
||||
props: {
|
||||
content: page.data,
|
||||
pageUrl: slug,
|
||||
title: page.title,
|
||||
meta: meta({
|
||||
title: page.title,
|
||||
image: image.src,
|
||||
imageWidth: image.width,
|
||||
imageHeight: image.height,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const unstable_getStaticPaths = async () => {
|
||||
console.log('call all unstable_getStaticPaths')
|
||||
|
||||
const urls = await requestGet<IResponseItems<string>>(createApiUrl(`/api/pages/urls`), null)
|
||||
if (!urls) {
|
||||
return null
|
||||
}
|
||||
|
||||
return {
|
||||
paths: urls.items
|
||||
.map(path => {
|
||||
const slug = tail(path.split('/'))
|
||||
|
||||
return {
|
||||
params: {
|
||||
slug,
|
||||
},
|
||||
}
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
export default Index
|
||||
+4
-35
@@ -1,43 +1,12 @@
|
||||
import React from 'react'
|
||||
import App, { Container } from 'next/app'
|
||||
import 'src/style.css'
|
||||
import App from 'next/app'
|
||||
|
||||
class MyApp extends App {
|
||||
export default class MyApp extends App {
|
||||
render() {
|
||||
const { Component, pageProps } = this.props
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<style global jsx>{`
|
||||
@media (max-width: 31.25em) {
|
||||
:root {
|
||||
--smaller-font-size: 0.9rem;
|
||||
--normal-font-size: 1rem;
|
||||
--bigger-font-size: 1.1rem;
|
||||
--big-font-size: 1.3rem;
|
||||
--biggest-font-size: 2rem;
|
||||
|
||||
--font-size-h1: 1.5rem;
|
||||
--font-size-h2: 1.5rem;
|
||||
--font-size-h3: 1.25rem;
|
||||
|
||||
--content-thin: 90%;
|
||||
--content-wide: 90%;
|
||||
}
|
||||
}
|
||||
|
||||
.noscroll {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#__next {
|
||||
height: 100%;
|
||||
}
|
||||
`}</style>
|
||||
|
||||
<Component {...pageProps} />
|
||||
</Container>
|
||||
<Component {...pageProps} />
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default MyApp
|
||||
@@ -1,20 +1,12 @@
|
||||
import React from 'react'
|
||||
import Document, { Html, Head, Main, NextScript } from 'next/document'
|
||||
import { YMetrika } from '../src/components/YMetrika'
|
||||
import { GAnalytics } from '../src/components/GAnalytics'
|
||||
import { YMetrika } from 'src/components/YMetrika'
|
||||
import { GAnalytics } from 'src/components/GAnalytics'
|
||||
|
||||
export default class MyDocument extends Document {
|
||||
// static async getInitialProps(ctx) {
|
||||
// const initialProps = await Document.getInitialProps(ctx);
|
||||
// return { ...initialProps };
|
||||
// }
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Html>
|
||||
<Head>
|
||||
<style>{`body { margin: 0 } /* custom! */`}</style>
|
||||
|
||||
<meta charSet="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, maximum-scale=1.0" />
|
||||
<meta name="referrer" content="unsafe-url" />
|
||||
@@ -62,11 +54,11 @@ export default class MyDocument extends Document {
|
||||
<GAnalytics account={'UA-60209057-1'} />
|
||||
</Head>
|
||||
|
||||
<body className="custom_class">
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
);
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react'
|
||||
import '../src/style/style.scss'
|
||||
import 'src/style/style.scss'
|
||||
import { NextPage } from 'next'
|
||||
|
||||
const Page = props => (
|
||||
const Page: NextPage = () => (
|
||||
<div className="body-wrapper">
|
||||
<main className="body-wrapper__content">
|
||||
<section className="error-404">
|
||||
@@ -22,4 +22,4 @@ const Page = props => (
|
||||
</div>
|
||||
)
|
||||
|
||||
export default Page
|
||||
export default Page
|
||||
@@ -1,43 +0,0 @@
|
||||
import React from 'react'
|
||||
import Head from 'next/head'
|
||||
import { App } from '../../src/components/App'
|
||||
import Article from '../../src/components/Article'
|
||||
import Html from '../../src/components/Html'
|
||||
import menuModel from '../../src/models/menu'
|
||||
import { buildMenu } from '../../src/lib/menu'
|
||||
import { createApiUrl, requestGet, wrapInitialProps } from '../../src/next-lib'
|
||||
|
||||
const Page = (props) => (
|
||||
<App
|
||||
menu={buildMenu(props.pageUrl, menuModel)}
|
||||
showAuthor={true}
|
||||
menuPadding={true}
|
||||
layout={'thin'}
|
||||
>
|
||||
<Head>
|
||||
<title>{props.album.title}</title>
|
||||
</Head>
|
||||
<Article
|
||||
title={props.album.title}
|
||||
date={props.album.date}
|
||||
shareable={true}
|
||||
>
|
||||
<Html
|
||||
html={props.album.post}
|
||||
/>
|
||||
</Article>
|
||||
</App>
|
||||
)
|
||||
|
||||
Page.getInitialProps = wrapInitialProps(async (ctx) => {
|
||||
const pageUrl = '/gallery'
|
||||
const id = ctx.query.album
|
||||
const album = await requestGet(createApiUrl(ctx.req, `/api/albums/${id}`), {})
|
||||
|
||||
return {
|
||||
album,
|
||||
pageUrl,
|
||||
}
|
||||
})
|
||||
|
||||
export default Page
|
||||
@@ -0,0 +1,86 @@
|
||||
import Head from 'next/head'
|
||||
import { App } from 'src/components/App'
|
||||
import Article from 'src/components/Article'
|
||||
import { Html } from 'src/components/Html'
|
||||
import menuModel from 'src/models/menu'
|
||||
import { buildMenu } from 'src/lib/menu'
|
||||
import { createApiUrl, requestGet, IResponseItems } from 'src/next-lib'
|
||||
import { NextPage } from 'next'
|
||||
|
||||
type Props = {
|
||||
pageUrl: string
|
||||
data: any //(album)
|
||||
}
|
||||
|
||||
const Page: NextPage<Props> = props => {
|
||||
if (!props?.data) {
|
||||
console.log('kek error', props)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<App
|
||||
menu={buildMenu(props.pageUrl, menuModel)}
|
||||
showAuthor={true}
|
||||
menuPadding={true}
|
||||
layout={'thin'}
|
||||
>
|
||||
<Head>
|
||||
<title>{props.data.title}</title>
|
||||
</Head>
|
||||
|
||||
<Article
|
||||
title={props.data.title}
|
||||
date={props.data.date}
|
||||
shareable={true}
|
||||
tags={[]}
|
||||
>
|
||||
<Html
|
||||
html={props.data.post}
|
||||
/>
|
||||
</Article>
|
||||
</App>
|
||||
)
|
||||
}
|
||||
|
||||
export const unstable_getStaticProps = async (ctx: any) => {
|
||||
const pageUrl = '/gallery'
|
||||
// const id = ctx.query.slug
|
||||
const id = ctx.params.slug
|
||||
const data = await requestGet(createApiUrl(`/api/albums/${id}`), null)
|
||||
|
||||
if (!data) {
|
||||
throw new Error(`kek ${id}`)
|
||||
}
|
||||
|
||||
return {
|
||||
props: {
|
||||
data,
|
||||
pageUrl,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const unstable_getStaticPaths = async () => {
|
||||
console.log('call album unstable_getStaticPaths')
|
||||
|
||||
const urls = await requestGet<IResponseItems<string>>(createApiUrl(`/api/albums/urls`), null)
|
||||
if (!urls) {
|
||||
return null
|
||||
}
|
||||
|
||||
return {
|
||||
paths: urls.items
|
||||
.map(x => x.replace('/album/', ''))
|
||||
.map(slug => {
|
||||
return {
|
||||
params: {
|
||||
slug,
|
||||
},
|
||||
}
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
export default Page
|
||||
@@ -1,19 +0,0 @@
|
||||
import { connect } from '../../../src/core/db'
|
||||
import Album from '../../../src/core/Album'
|
||||
import { withMiddleware } from '../../../src/middlewares/withMiddleware'
|
||||
|
||||
export default withMiddleware(async (req, res) => {
|
||||
await connect()
|
||||
|
||||
const id = req.query.album
|
||||
const album = await Album.findById(id)
|
||||
|
||||
if (album) {
|
||||
res.json(album)
|
||||
} else {
|
||||
res.status(404)
|
||||
res.json({
|
||||
error: `Album ${id} not found`
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -1,19 +0,0 @@
|
||||
import { connect } from '../../../src/core/db'
|
||||
import Album from '../../../src/core/Album'
|
||||
import { withMiddleware } from '../../../src/middlewares/withMiddleware'
|
||||
|
||||
export default withMiddleware(async (req, res) => {
|
||||
await connect()
|
||||
|
||||
const data = await Album.find({}, { sort: { date: -1 } })
|
||||
if (data) {
|
||||
res.json({
|
||||
items: data,
|
||||
})
|
||||
} else {
|
||||
res.status(404)
|
||||
res.json({
|
||||
error: `Article not found`
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -1,20 +0,0 @@
|
||||
import { connect } from '../../../src/core/db'
|
||||
import Album from '../../../src/core/Album'
|
||||
|
||||
export default async (req, res) => {
|
||||
await connect()
|
||||
|
||||
const data = await Album.find({})
|
||||
|
||||
if (data) {
|
||||
const items = data.map(x => `/album/${x.id}`)
|
||||
res.json({
|
||||
items
|
||||
})
|
||||
} else {
|
||||
res.status(404)
|
||||
res.json({
|
||||
error: `Not found`
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
import Article from '../../../src/core/Article'
|
||||
import { encodeArticle } from '../../../src/server/articles'
|
||||
import { withMiddleware } from '../../../src/middlewares/withMiddleware'
|
||||
|
||||
export default withMiddleware(async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
const {
|
||||
query: { article: id }
|
||||
} = req;
|
||||
|
||||
const article = await Article.findById(id)
|
||||
|
||||
if (article) {
|
||||
res.json(encodeArticle(article))
|
||||
} else {
|
||||
res.status(404)
|
||||
res.json({
|
||||
error: `Article ${id} not found`
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -1,24 +0,0 @@
|
||||
import { findArticles } from '../../../src/server/articles'
|
||||
import { withMiddleware } from '../../../src/middlewares/withMiddleware'
|
||||
|
||||
const int = (value: string | string[]) => parseInt(Array.isArray(value)
|
||||
? value[0]
|
||||
: value
|
||||
)
|
||||
|
||||
export default withMiddleware(async (req, res) => {
|
||||
const { query } = req
|
||||
const page = int(query.page)
|
||||
const pageSize = int(query.pageSize)
|
||||
|
||||
const data = await findArticles(page, pageSize)
|
||||
|
||||
if (data) {
|
||||
res.json(data)
|
||||
} else {
|
||||
res.status(404)
|
||||
res.json({
|
||||
error: `Articles not found`
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -1,21 +0,0 @@
|
||||
import { connect } from '../../../src/core/db'
|
||||
import Article from '../../../src/core/Article'
|
||||
import { withMiddleware } from '../../../src/middlewares/withMiddleware'
|
||||
|
||||
export default withMiddleware(async (req, res) => {
|
||||
await connect()
|
||||
|
||||
const data = await Article.find({})
|
||||
|
||||
if (data) {
|
||||
const items = data.map(x => `/article/${x.id}`)
|
||||
res.json({
|
||||
items
|
||||
})
|
||||
} else {
|
||||
res.status(404)
|
||||
res.json({
|
||||
error: `Not found`
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -1,20 +0,0 @@
|
||||
import { connect } from '../../../src/core/db'
|
||||
import Document from '../../../src/core/Document'
|
||||
import { encodeFile } from '../../../src/api/files'
|
||||
import { withMiddleware } from '../../../src/middlewares/withMiddleware'
|
||||
|
||||
export default withMiddleware(async (req, res) => {
|
||||
await connect()
|
||||
|
||||
const id = req.query.document
|
||||
const document = await Document.findById(id)
|
||||
|
||||
if (document) {
|
||||
res.json(encodeFile(document))
|
||||
} else {
|
||||
res.status(404)
|
||||
res.json({
|
||||
error: `Document ${id} not found`
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -1,24 +0,0 @@
|
||||
import { connect } from '../../../src/core/db'
|
||||
import Document from '../../../src/core/Document'
|
||||
import { encodeFile } from '../../../src/api/files'
|
||||
import { withMiddleware } from '../../../src/middlewares/withMiddleware'
|
||||
|
||||
export default withMiddleware(async (req, res) => {
|
||||
await connect()
|
||||
|
||||
const documents = await Document.find({hidden: false})
|
||||
if (documents) {
|
||||
const items = documents
|
||||
.map(encodeFile)
|
||||
.filter(x => x.imageUrl) // skip documents without preview image; needs to be refactored
|
||||
|
||||
res.json({
|
||||
items,
|
||||
})
|
||||
} else {
|
||||
res.status(404)
|
||||
res.json({
|
||||
error: `Documents not found`
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -1,21 +0,0 @@
|
||||
import { connect } from '../../../src/core/db'
|
||||
import Document from '../../../src/core/Document'
|
||||
import { withMiddleware } from '../../../src/middlewares/withMiddleware'
|
||||
|
||||
export default withMiddleware(async (req, res) => {
|
||||
await connect()
|
||||
|
||||
const data = await Document.find({})
|
||||
|
||||
if (data) {
|
||||
const items = data.map(x => `/document/${x.id}`)
|
||||
res.json({
|
||||
items
|
||||
})
|
||||
} else {
|
||||
res.status(404)
|
||||
res.json({
|
||||
error: `Not found`
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -1,17 +0,0 @@
|
||||
import Image from '../../src/core/Image'
|
||||
import { encodeImage } from '../../src/api/image'
|
||||
import { withMiddleware } from '../../src/middlewares/withMiddleware'
|
||||
|
||||
export default withMiddleware(async (req, res) => {
|
||||
const file = req.query.file
|
||||
const image = await Image.findByFile(file)
|
||||
|
||||
if (image) {
|
||||
res.json(encodeImage(image))
|
||||
} else {
|
||||
res.status(404)
|
||||
res.json({
|
||||
error: `Image ${file} not found`
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -1,21 +0,0 @@
|
||||
import { connect } from '../../src/core/db'
|
||||
import Page from '../../src/core/Page'
|
||||
import { getPathWithNoTrailingSlash } from '../../src/lib/url'
|
||||
import { encodePage } from '../../src/api/page'
|
||||
import { withMiddleware } from '../../src/middlewares/withMiddleware'
|
||||
|
||||
export default withMiddleware(async (req, res) => {
|
||||
await connect()
|
||||
|
||||
const page = getPathWithNoTrailingSlash(req.query.page)
|
||||
const resource = await Page.findByUrl(page)
|
||||
|
||||
if (resource) {
|
||||
res.json(encodePage(resource))
|
||||
} else {
|
||||
res.status(404)
|
||||
res.json({
|
||||
error: `Image ${page} not found`
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -1,17 +0,0 @@
|
||||
import Page from '../../../src/core/Page'
|
||||
import { withMiddleware } from '../../../src/middlewares/withMiddleware'
|
||||
|
||||
export default withMiddleware(async (req, res) => {
|
||||
const items = await Page.find({})
|
||||
|
||||
if (items) {
|
||||
res.json({
|
||||
items,
|
||||
})
|
||||
} else {
|
||||
res.status(404)
|
||||
res.json({
|
||||
error: `Article ${id} not found`
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -1,21 +0,0 @@
|
||||
import { connect } from '../../../src/core/db'
|
||||
import Page from '../../../src/core/Page'
|
||||
import { withMiddleware } from '../../../src/middlewares/withMiddleware'
|
||||
|
||||
export default withMiddleware(async (req, res) => {
|
||||
await connect()
|
||||
|
||||
const data = await Page.find({})
|
||||
if (data) {
|
||||
const items = data.map(x => x.url)
|
||||
|
||||
res.json({
|
||||
items,
|
||||
})
|
||||
} else {
|
||||
res.status(404)
|
||||
res.json({
|
||||
error: `Not found`
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -1,20 +0,0 @@
|
||||
import { connect } from '../../../src/core/db'
|
||||
import Teacher from '../../../src/core/Teacher'
|
||||
import { encodePerson } from '../../../src/api/persons'
|
||||
import { withMiddleware } from '../../../src/middlewares/withMiddleware'
|
||||
|
||||
export default withMiddleware(async (req, res) => {
|
||||
await connect()
|
||||
|
||||
const id = req.query.person
|
||||
const data = await Teacher.findById(id)
|
||||
|
||||
if (data) {
|
||||
res.json(encodePerson(data))
|
||||
} else {
|
||||
res.status(404)
|
||||
res.json({
|
||||
error: `Article ${id} not found`
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -1,33 +0,0 @@
|
||||
import { connect } from '../../../src/core/db'
|
||||
import Teacher from '../../../src/core/Teacher'
|
||||
import { prioritySort } from '../../../src/lib/sort'
|
||||
import { encodePerson } from '../../../src/api/persons'
|
||||
import { withMiddleware } from '../../../src/middlewares/withMiddleware'
|
||||
|
||||
export default withMiddleware(async (req, res) => {
|
||||
await connect()
|
||||
|
||||
const order = [
|
||||
'mg-timasheva',
|
||||
'va-sarzhin',
|
||||
'od-gogoleva',
|
||||
'my-valkova',
|
||||
'nv-andreeva',
|
||||
'vv-voronova',
|
||||
]
|
||||
const teachersSorted = prioritySort.bind(null, [...order], t => t.id)
|
||||
|
||||
const teachers = await Teacher.find({ hidden: false })
|
||||
const data = teachersSorted(teachers).map(encodePerson)
|
||||
|
||||
if (data) {
|
||||
res.json({
|
||||
items: data,
|
||||
})
|
||||
} else {
|
||||
res.status(404)
|
||||
res.json({
|
||||
error: `Article ${id} not found`
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -1,21 +0,0 @@
|
||||
import { connect } from '../../../src/core/db'
|
||||
import Teacher from '../../../src/core/Teacher'
|
||||
import { withMiddleware } from '../../../src/middlewares/withMiddleware'
|
||||
|
||||
export default withMiddleware(async (req, res) => {
|
||||
await connect()
|
||||
|
||||
const data = await Teacher.find({})
|
||||
|
||||
if (data) {
|
||||
const items = data.map(x => `/teacher/${x.id}`)
|
||||
res.json({
|
||||
items
|
||||
})
|
||||
} else {
|
||||
res.status(404)
|
||||
res.json({
|
||||
error: `Not found`
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -1,18 +0,0 @@
|
||||
import { findSchedule } from '../../src/server/schedule'
|
||||
import { withMiddleware } from '../../src/middlewares/withMiddleware'
|
||||
|
||||
export default withMiddleware(async (req, res) => {
|
||||
|
||||
const period = req.query.period
|
||||
const semester = req.query.semester
|
||||
const data = await findSchedule(req.collection, period, semester)
|
||||
|
||||
if (data) {
|
||||
res.json(data)
|
||||
} else {
|
||||
res.status(404)
|
||||
res.json({
|
||||
error: `Schedule ${period}:${semester} not found`
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -1,55 +0,0 @@
|
||||
import React from 'react'
|
||||
import Head from 'next/head'
|
||||
import { get } from 'lodash'
|
||||
import { App } from '../../src/components/App'
|
||||
import Article from '../../src/components/Article'
|
||||
import Html from '../../src/components/Html'
|
||||
import menuModel from '../../src/models/menu'
|
||||
import { buildMenu } from '../../src/lib/menu'
|
||||
import { Meta } from '../../src/components/Meta'
|
||||
import { meta } from '../../src/lib/meta'
|
||||
import { createApiUrl, requestGet, wrapInitialProps } from '../../src/next-lib'
|
||||
|
||||
const Page = (props) => (
|
||||
<App
|
||||
menu={buildMenu(props.pageUrl, menuModel)}
|
||||
showAuthor={true}
|
||||
menuPadding={true}
|
||||
layout={'thin'}
|
||||
>
|
||||
<Head>
|
||||
<title>{props.article.title}</title>
|
||||
<Meta meta={props.meta} />
|
||||
</Head>
|
||||
<Article
|
||||
title={props.article.title}
|
||||
date={props.article.date}
|
||||
tags={props.article.tags}
|
||||
shareable={true}
|
||||
>
|
||||
<Html
|
||||
html={props.article.post}
|
||||
/>
|
||||
</Article>
|
||||
</App>
|
||||
)
|
||||
|
||||
Page.getInitialProps = wrapInitialProps(async (ctx) => {
|
||||
const pageUrl = '/'
|
||||
const id = ctx.query.article
|
||||
const article = await requestGet(createApiUrl(ctx.req, `/api/articles/${id}`), {})
|
||||
const image = get(article, 'preview.artifacts.fb', {})
|
||||
|
||||
return {
|
||||
article,
|
||||
pageUrl,
|
||||
meta: meta({
|
||||
title: article.title,
|
||||
image: image.src,
|
||||
imageWidth: image.width,
|
||||
imageHeight: image.height,
|
||||
}),
|
||||
}
|
||||
})
|
||||
|
||||
export default Page
|
||||
@@ -0,0 +1,95 @@
|
||||
import Head from 'next/head'
|
||||
import { get } from 'lodash'
|
||||
import { App } from 'src/components/App'
|
||||
import Article from 'src/components/Article'
|
||||
import { Html } from 'src/components/Html'
|
||||
import menuModel from 'src/models/menu'
|
||||
import { buildMenu } from 'src/lib/menu'
|
||||
import { Meta } from 'src/components/Meta'
|
||||
import { meta } from 'src/lib/meta'
|
||||
import { createApiUrl, requestGet, IResponseItems } from 'src/next-lib'
|
||||
import { NextPage } from 'next'
|
||||
|
||||
type Props = {
|
||||
pageUrl: string
|
||||
meta: any
|
||||
data: any //(article)
|
||||
}
|
||||
|
||||
const Page: NextPage<Props> = props => {
|
||||
if (!props.data) {
|
||||
console.log('kek error', props)
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<App
|
||||
menu={buildMenu(props.pageUrl, menuModel)}
|
||||
showAuthor={true}
|
||||
menuPadding={true}
|
||||
layout={'thin'}
|
||||
>
|
||||
<Head>
|
||||
<title>{props.data.title}</title>
|
||||
<Meta meta={props.meta} />
|
||||
</Head>
|
||||
<Article
|
||||
title={props.data.title}
|
||||
date={props.data.date}
|
||||
tags={props.data.tags}
|
||||
shareable={true}
|
||||
>
|
||||
<Html
|
||||
html={props.data.post}
|
||||
/>
|
||||
</Article>
|
||||
</App>
|
||||
)
|
||||
}
|
||||
|
||||
export const unstable_getStaticProps = async (ctx: any) => {
|
||||
const pageUrl = '/'
|
||||
const id = ctx.params.slug
|
||||
const data = await requestGet(createApiUrl(`/api/articles/${id}`), null)
|
||||
if (!data) {
|
||||
return null
|
||||
}
|
||||
|
||||
const image = get(data, 'preview.artifacts.fb', {})
|
||||
|
||||
return {
|
||||
props: {
|
||||
data,
|
||||
pageUrl,
|
||||
meta: meta({
|
||||
title: data.title,
|
||||
image: image.src,
|
||||
imageWidth: image.width,
|
||||
imageHeight: image.height,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const unstable_getStaticPaths = async () => {
|
||||
console.log('call article unstable_getStaticPaths')
|
||||
|
||||
const urls = await requestGet<IResponseItems<string>>(createApiUrl(`/api/articles/urls`), null)
|
||||
if (!urls) {
|
||||
return null
|
||||
}
|
||||
|
||||
return {
|
||||
paths: urls.items
|
||||
.map(x => x.replace('/article/', ''))
|
||||
.map(slug => {
|
||||
return {
|
||||
params: {
|
||||
slug,
|
||||
},
|
||||
}
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
export default Page
|
||||
@@ -1,52 +0,0 @@
|
||||
import React from 'react'
|
||||
import Head from 'next/head'
|
||||
import { App } from '../../src/components/App'
|
||||
import { ArticleCardList } from '../../src/components/ArticleCardList'
|
||||
import menuModel from '../../src/models/menu'
|
||||
import { buildMenu } from '../../src/lib/menu'
|
||||
import { meta } from '../../src/lib/meta'
|
||||
import { Meta } from '../../src/components/Meta'
|
||||
import { createApiUrl, requestGet, wrapInitialProps } from '../../src/next-lib'
|
||||
|
||||
const Page = (props) => (
|
||||
<App
|
||||
menu={buildMenu(props.pageUrl, menuModel)}
|
||||
showAuthor={true}
|
||||
menuPadding={true}
|
||||
layout={'wide'}
|
||||
>
|
||||
<Head>
|
||||
<title>{props.title}</title>
|
||||
<Meta meta={props.meta} />
|
||||
</Head>
|
||||
<ArticleCardList
|
||||
articles={props.articles}
|
||||
prevPage={props.prevPage}
|
||||
nextPage={props.nextPage}
|
||||
/>
|
||||
</App>
|
||||
)
|
||||
|
||||
Page.getInitialProps = wrapInitialProps(async (ctx) => {
|
||||
const pageUrl = '/'
|
||||
const page = parseInt(ctx.query.page)
|
||||
const pageSize = parseInt(ctx.query.pageSize) || 15
|
||||
const res = await requestGet(createApiUrl(ctx.req, `/api/articles?page=${page}&pageSize=${pageSize}`), {})
|
||||
const articles = res.items || []
|
||||
const nextPage = res.nextPage
|
||||
const prevPage = res.prevPage
|
||||
const title = 'События'
|
||||
|
||||
return {
|
||||
articles,
|
||||
nextPage,
|
||||
prevPage,
|
||||
pageUrl,
|
||||
title,
|
||||
meta: meta({
|
||||
title,
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
export default Page
|
||||
@@ -0,0 +1,104 @@
|
||||
import Head from 'next/head'
|
||||
import { range } from 'lodash'
|
||||
import { App } from 'src/components/App'
|
||||
import { ArticleCardList } from 'src/components/ArticleCardList'
|
||||
import menuModel from 'src/models/menu'
|
||||
import { buildMenu } from 'src/lib/menu'
|
||||
import { meta } from 'src/lib/meta'
|
||||
import { Meta } from 'src/components/Meta'
|
||||
import { createApiUrl, requestGet, IResponseItems } from 'src/next-lib'
|
||||
import { NextPage } from 'next'
|
||||
|
||||
const pageSize = Number(process.env.APP_ARTICLES_PAGE_SIZE)
|
||||
|
||||
type Props = {
|
||||
pageUrl: string
|
||||
meta: any
|
||||
title: string
|
||||
data: any //(list of article)
|
||||
nextPage: number
|
||||
prevPage: number
|
||||
}
|
||||
|
||||
const Page: NextPage<Props> = props => {
|
||||
if (!props.data) {
|
||||
console.log('kek error', props)
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<App
|
||||
menu={buildMenu(props.pageUrl, menuModel)}
|
||||
showAuthor={true}
|
||||
menuPadding={true}
|
||||
layout={'wide'}
|
||||
>
|
||||
<Head>
|
||||
<title>{props.title}</title>
|
||||
<Meta meta={props.meta} />
|
||||
</Head>
|
||||
<ArticleCardList
|
||||
articles={props.data}
|
||||
prevPage={props.prevPage}
|
||||
nextPage={props.nextPage}
|
||||
/>
|
||||
</App>
|
||||
)
|
||||
}
|
||||
|
||||
export const unstable_getStaticProps = async (ctx: any) => {
|
||||
const pageUrl = '/'
|
||||
// const page = parseInt(ctx.query.page)
|
||||
const page = parseInt(ctx.params.slug)
|
||||
const res = await requestGet<IResponseItems<any[]>>(
|
||||
createApiUrl(`/api/articles?page=${page}&pageSize=${pageSize}`),
|
||||
null
|
||||
)
|
||||
if (!res) {
|
||||
return null
|
||||
}
|
||||
|
||||
const data = res.items || []
|
||||
const nextPage = (res as any).nextPage
|
||||
const prevPage = (res as any).prevPage
|
||||
const title = 'События'
|
||||
|
||||
return {
|
||||
props: {
|
||||
data,
|
||||
nextPage,
|
||||
prevPage,
|
||||
pageUrl,
|
||||
title,
|
||||
meta: meta({
|
||||
title,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const unstable_getStaticPaths = async () => {
|
||||
console.log('call articles unstable_getStaticPaths')
|
||||
|
||||
const urls = await requestGet<IResponseItems<string>>(createApiUrl(`/api/articles/urls`), null)
|
||||
if (!urls) {
|
||||
return null
|
||||
}
|
||||
|
||||
const count = urls.items.length
|
||||
const pages = Math.ceil(count / pageSize)
|
||||
|
||||
return {
|
||||
paths: range(1, pages + 1)
|
||||
.map(i => {
|
||||
return {
|
||||
params: {
|
||||
slug: `${i}`,
|
||||
},
|
||||
}
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default Page
|
||||
@@ -1,73 +0,0 @@
|
||||
import React from 'react'
|
||||
import Head from 'next/head'
|
||||
import { get } from 'lodash'
|
||||
import { App } from '../src/components/App'
|
||||
import { Meta } from '../src/components/Meta'
|
||||
import { CollectiveImage } from '../src/components/CollectiveImage'
|
||||
import { PersonCard } from '../src/components/PersonCard'
|
||||
import { CardList } from '../src/components/CardList'
|
||||
import menuModel from '../src/models/menu'
|
||||
import { buildMenu } from '../src/lib/menu'
|
||||
import { meta } from '../src/lib/meta'
|
||||
import { createApiUrl, requestGet, wrapInitialProps } from '../src/next-lib'
|
||||
|
||||
const Page = (props) => (
|
||||
<App
|
||||
menu={buildMenu(props.pageUrl, menuModel)}
|
||||
showAuthor={true}
|
||||
menuPadding={true}
|
||||
layout={'wide'}
|
||||
>
|
||||
<Head>
|
||||
<title>{props.title}</title>
|
||||
<Meta meta={props.meta} />
|
||||
</Head>
|
||||
|
||||
{!props.image ? null : (
|
||||
<CollectiveImage
|
||||
data={props.image}
|
||||
style={{
|
||||
marginBottom: 'var(--double-margin)',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
<CardList
|
||||
items={props.persons}
|
||||
renderItem={(person, index) => (
|
||||
<PersonCard
|
||||
key={index}
|
||||
profile={person}
|
||||
picture={person.picture}
|
||||
url={person.url}
|
||||
name={person.name}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</App>
|
||||
)
|
||||
|
||||
Page.getInitialProps = wrapInitialProps(async (ctx) => {
|
||||
const pageUrl = ctx.req.url
|
||||
|
||||
const res = await requestGet(createApiUrl(ctx.req, '/api/persons'), {})
|
||||
const persons = res.items || []
|
||||
const title = 'Преподаватели Шлиссельбургской ДХШ'
|
||||
const imageFile = 'Images/HudozkaCollective2017.jpg'
|
||||
const resImage = await requestGet(createApiUrl(ctx.req, `/api/image?file=${imageFile}`), null)
|
||||
const image = get(resImage, 'artifacts.large', null)
|
||||
|
||||
return {
|
||||
persons,
|
||||
image,
|
||||
pageUrl,
|
||||
title,
|
||||
meta: meta({
|
||||
title,
|
||||
url: pageUrl,
|
||||
description: 'Преподаватели Шлиссельбургской ДХШ',
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
export default Page
|
||||
@@ -0,0 +1,96 @@
|
||||
import Head from 'next/head'
|
||||
import { get } from 'lodash'
|
||||
import { App } from 'src/components/App'
|
||||
import { Meta } from 'src/components/Meta'
|
||||
import { CollectiveImage } from 'src/components/CollectiveImage'
|
||||
import { PersonCard } from 'src/components/PersonCard'
|
||||
import { CardList } from 'src/components/CardList'
|
||||
import menuModel from 'src/models/menu'
|
||||
import { buildMenu } from 'src/lib/menu'
|
||||
import { meta } from 'src/lib/meta'
|
||||
import { IMeta } from 'src/types'
|
||||
import { createApiUrl, requestGet, IResponseItems } from 'src/next-lib'
|
||||
import { NextPage, NextPageContext } from 'next'
|
||||
|
||||
interface IPerson {
|
||||
|
||||
}
|
||||
|
||||
type Props = {
|
||||
pageUrl: string
|
||||
title: string
|
||||
image: string
|
||||
meta: IMeta
|
||||
data: IPerson[]
|
||||
}
|
||||
|
||||
const Page: NextPage<Props> = props => {
|
||||
if (!props.data) {
|
||||
console.log('kek error')
|
||||
return
|
||||
}
|
||||
|
||||
return (
|
||||
<App
|
||||
menu={buildMenu(props.pageUrl, menuModel)}
|
||||
showAuthor={true}
|
||||
menuPadding={true}
|
||||
layout={'wide'}
|
||||
>
|
||||
<Head>
|
||||
<title>{props.title}</title>
|
||||
<Meta meta={props.meta} />
|
||||
</Head>
|
||||
|
||||
{!props.image ? null : (
|
||||
<CollectiveImage
|
||||
data={props.image}
|
||||
style={{
|
||||
marginBottom: 'var(--double-margin)',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
<CardList
|
||||
items={props.data}
|
||||
renderItem={(person, index) => (
|
||||
<PersonCard
|
||||
key={index}
|
||||
profile={person}
|
||||
picture={person.picture}
|
||||
url={person.url}
|
||||
name={person.name}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</App>
|
||||
)
|
||||
}
|
||||
|
||||
export const unstable_getStaticProps = async (ctx: NextPageContext) => {
|
||||
// const pageUrl = ctx.req.url
|
||||
const pageUrl = '/collective'
|
||||
|
||||
const res = await requestGet<IResponseItems<IPerson>>(createApiUrl('/api/persons'), { items: [] })
|
||||
const data = res.items || []
|
||||
const title = 'Преподаватели Шлиссельбургской ДХШ'
|
||||
const imageFile = 'Images/HudozkaCollective2017.jpg'
|
||||
const resImage = await requestGet(createApiUrl(`/api/image?file=${imageFile}`), null)
|
||||
const image = get(resImage, 'artifacts.large', null)
|
||||
|
||||
return {
|
||||
props: {
|
||||
data,
|
||||
image,
|
||||
pageUrl,
|
||||
title,
|
||||
meta: meta({
|
||||
title,
|
||||
url: pageUrl,
|
||||
description: 'Преподаватели Шлиссельбургской ДХШ',
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Page
|
||||
@@ -1,42 +0,0 @@
|
||||
import React from 'react'
|
||||
import Head from 'next/head'
|
||||
import { App } from '../../src/components/App'
|
||||
import Document from '../../src/components/Document'
|
||||
import { Share } from '../../src/components/Share'
|
||||
import menuModel from '../../src/models/menu'
|
||||
import { buildMenu } from '../../src/lib/menu'
|
||||
import { meta } from '../../src/lib/meta'
|
||||
import { Meta } from '../../src/components/Meta'
|
||||
import { createApiUrl, requestGet, wrapInitialProps } from '../../src/next-lib'
|
||||
|
||||
const Page = (props) => (
|
||||
<App
|
||||
menu={buildMenu(props.pageUrl, menuModel)}
|
||||
showAuthor={true}
|
||||
menuPadding={true}
|
||||
layout={'wide'}
|
||||
>
|
||||
<Head>
|
||||
<title>{props.file.title}</title>
|
||||
<Meta meta={props.meta} />
|
||||
</Head>
|
||||
<Document {...props.file} />
|
||||
<Share />
|
||||
</App>
|
||||
)
|
||||
|
||||
Page.getInitialProps = wrapInitialProps(async (ctx) => {
|
||||
const pageUrl = '/documents'
|
||||
const id = ctx.query.document
|
||||
const file = await requestGet(createApiUrl(ctx.req, `/api/files/${id}`), {})
|
||||
|
||||
return {
|
||||
file,
|
||||
pageUrl,
|
||||
meta: meta({
|
||||
title: file.meta,
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
export default Page
|
||||
@@ -0,0 +1,81 @@
|
||||
import React from 'react'
|
||||
import Head from 'next/head'
|
||||
import { App } from 'src/components/App'
|
||||
import Document from 'src/components/Document'
|
||||
import { Share } from 'src/components/Share'
|
||||
import menuModel from 'src/models/menu'
|
||||
import { buildMenu } from 'src/lib/menu'
|
||||
import { meta } from 'src/lib/meta'
|
||||
import { Meta } from 'src/components/Meta'
|
||||
import { createApiUrl, requestGet, IResponseItems } from 'src/next-lib'
|
||||
import { NextPage } from 'next'
|
||||
import { IMeta } from 'src/types'
|
||||
|
||||
type Props = {
|
||||
pageUrl: string
|
||||
data: any //(file)
|
||||
meta: IMeta
|
||||
}
|
||||
|
||||
const Page: NextPage<Props> = props => {
|
||||
if (!props.data) {
|
||||
console.log('kek error', props)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<App
|
||||
menu={buildMenu(props.pageUrl, menuModel)}
|
||||
showAuthor={true}
|
||||
menuPadding={true}
|
||||
layout={'wide'}
|
||||
>
|
||||
<Head>
|
||||
<title>{props.data.title}</title>
|
||||
<Meta meta={props.meta} />
|
||||
</Head>
|
||||
<Document {...props.data} />
|
||||
<Share />
|
||||
</App>
|
||||
)
|
||||
}
|
||||
|
||||
export const unstable_getStaticProps = async (ctx: any) => {
|
||||
const pageUrl = '/documents'
|
||||
const id = ctx.params.slug
|
||||
const data = await requestGet(createApiUrl(`/api/files/${id}`), {})
|
||||
|
||||
return {
|
||||
props: {
|
||||
data,
|
||||
pageUrl,
|
||||
meta: meta({
|
||||
// title: file.meta,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const unstable_getStaticPaths = async () => {
|
||||
console.log('call file unstable_getStaticPaths')
|
||||
|
||||
const urls = await requestGet<IResponseItems<string>>(createApiUrl(`/api/files/urls`), null)
|
||||
if (!urls) {
|
||||
return null
|
||||
}
|
||||
|
||||
return {
|
||||
paths: urls.items
|
||||
.map(x => x.replace('/document/', ''))
|
||||
.map(slug => {
|
||||
return {
|
||||
params: {
|
||||
slug,
|
||||
},
|
||||
}
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
export default Page
|
||||
+21
-21
@@ -1,15 +1,13 @@
|
||||
import React from 'react'
|
||||
import Head from 'next/head'
|
||||
import { App } from '../src/components/App'
|
||||
import { Meta } from '../src/components/Meta'
|
||||
import menuModel from '../src/models/menu'
|
||||
import { buildMenu } from '../src/lib/menu'
|
||||
import { meta } from '../src/lib/meta'
|
||||
import { IDocument } from '../src/types'
|
||||
|
||||
import { DocumentList } from '../src/components/DocumentList'
|
||||
import { unique } from '../src/utils/common'
|
||||
import { createApiUrl, requestGet, wrapInitialProps, IResponseItems } from '../src/next-lib'
|
||||
import { App } from 'src/components/App'
|
||||
import { Meta } from 'src/components/Meta'
|
||||
import menuModel from 'src/models/menu'
|
||||
import { buildMenu } from 'src/lib/menu'
|
||||
import { meta } from 'src/lib/meta'
|
||||
import { IDocument } from 'src/types'
|
||||
import { DocumentList } from 'src/components/DocumentList'
|
||||
import { unique } from 'src/utils/common'
|
||||
import { createApiUrl, requestGet, IResponseItems } from 'src/next-lib'
|
||||
import { NextPage } from 'next'
|
||||
|
||||
interface IDocumentCategory {
|
||||
@@ -125,22 +123,24 @@ const Page: NextPage<IProps> = props => (
|
||||
</App>
|
||||
)
|
||||
|
||||
Page.getInitialProps = wrapInitialProps(async (ctx) => {
|
||||
export const unstable_getStaticProps = async (ctx) => {
|
||||
const pageUrl = '/documents'
|
||||
const res = await requestGet<IResponseItems<IDocument>>(createApiUrl(ctx.req, '/api/files'), { items: [] })
|
||||
const res = await requestGet<IResponseItems<IDocument>>(createApiUrl('/api/files'), { items: [] })
|
||||
const files = res.items
|
||||
const title = 'Документы'
|
||||
const collections = getSorted(files)
|
||||
|
||||
return {
|
||||
collections,
|
||||
pageUrl,
|
||||
title,
|
||||
meta: meta({
|
||||
props: {
|
||||
collections,
|
||||
pageUrl,
|
||||
title,
|
||||
description: 'Документы Шлиссельбургской ДХШ',
|
||||
})
|
||||
meta: meta({
|
||||
title,
|
||||
description: 'Документы Шлиссельбургской ДХШ',
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export default Page
|
||||
export default Page
|
||||
+24
-19
@@ -1,14 +1,13 @@
|
||||
import React from 'react'
|
||||
import Head from 'next/head'
|
||||
import { App } from '../src/components/App'
|
||||
import { Meta } from '../src/components/Meta'
|
||||
import menuModel from '../src/models/menu'
|
||||
import { buildMenu } from '../src/lib/menu'
|
||||
import { splitBy } from '../src/lib/array'
|
||||
import { meta } from '../src/lib/meta'
|
||||
import { createApiUrl, requestGet, wrapInitialProps } from '../src/next-lib'
|
||||
import { App } from 'src/components/App'
|
||||
import { Meta } from 'src/components/Meta'
|
||||
import menuModel from 'src/models/menu'
|
||||
import { buildMenu } from 'src/lib/menu'
|
||||
import { splitBy } from 'src/lib/array'
|
||||
import { meta } from 'src/lib/meta'
|
||||
import { createApiUrl, requestGet } from 'src/next-lib'
|
||||
import { NextPage } from 'next'
|
||||
import { PageHeader } from '../src/components/PageHeader'
|
||||
import { PageHeader } from 'src/components/PageHeader'
|
||||
|
||||
const albumsByYear = splitBy(album => new Date(album.date).getFullYear())
|
||||
|
||||
@@ -96,22 +95,28 @@ const Page: NextPage<IProps> = props => (
|
||||
</App>
|
||||
)
|
||||
|
||||
Page.getInitialProps = wrapInitialProps(async (ctx) => {
|
||||
const pageUrl = ctx.req.url
|
||||
const res = await requestGet<any>(createApiUrl(ctx.req, `/api/albums`), {})
|
||||
export const unstable_getStaticProps = async (ctx: any) => {
|
||||
// const pageUrl = ctx.req.url
|
||||
const pageUrl = '/gallery'
|
||||
const res = await requestGet<any>(createApiUrl(`/api/albums`), null)
|
||||
if (!res) {
|
||||
return null
|
||||
}
|
||||
const items = res.items || []
|
||||
const albumCollections = albumsByYear(items)
|
||||
const title = 'Галерея'
|
||||
|
||||
return {
|
||||
collections: [...albumCollections.entries()],
|
||||
pageUrl,
|
||||
title,
|
||||
meta: meta({
|
||||
props: {
|
||||
collections: [...albumCollections.entries()],
|
||||
pageUrl,
|
||||
title,
|
||||
description: 'Галерея работ учащихся Шлиссельбургской Детской Художественной Школы'
|
||||
})
|
||||
meta: meta({
|
||||
title,
|
||||
description: 'Галерея работ учащихся Шлиссельбургской Детской Художественной Школы'
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export default Page
|
||||
+23
-22
@@ -1,13 +1,12 @@
|
||||
import React from 'react'
|
||||
import Head from 'next/head'
|
||||
import { App } from '../src/components/App'
|
||||
import { Meta } from '../src/components/Meta'
|
||||
import { ArticleCardList } from '../src/components/ArticleCardList'
|
||||
import { HudozkaTitle } from '../src/components/HudozkaTitle'
|
||||
import menuModel from '../src/models/menu'
|
||||
import { meta } from '../src/lib/meta'
|
||||
import { buildMenu } from '../src/lib/menu'
|
||||
import { createApiUrl, requestGet, wrapInitialProps } from '../src/next-lib'
|
||||
import { App } from 'src/components/App'
|
||||
import { Meta } from 'src/components/Meta'
|
||||
import { ArticleCardList } from 'src/components/ArticleCardList'
|
||||
import { HudozkaTitle } from 'src/components/HudozkaTitle'
|
||||
import menuModel from 'src/models/menu'
|
||||
import { meta } from 'src/lib/meta'
|
||||
import { buildMenu } from 'src/lib/menu'
|
||||
import { createApiUrl, requestGet } from 'src/next-lib'
|
||||
import { NextPage } from 'next'
|
||||
|
||||
interface IProps {
|
||||
@@ -41,27 +40,29 @@ const Page: NextPage<IProps> = props => (
|
||||
</App>
|
||||
)
|
||||
|
||||
Page.getInitialProps = wrapInitialProps(async (ctx) => {
|
||||
export const unstable_getStaticProps = async () => {
|
||||
const pageUrl = '/'
|
||||
const page = 1
|
||||
const pageSize = ctx.query.pageSize || 15
|
||||
const res = await requestGet(createApiUrl(ctx.req, `/api/articles?page=${page}&pageSize=${pageSize}`), {}) as any
|
||||
const pageSize = process.env.APP_ARTICLES_PAGE_SIZE
|
||||
const res = await requestGet(createApiUrl(`/api/articles?page=${page}&pageSize=${pageSize}`), {}) as any
|
||||
const articles = res.items || []
|
||||
const nextPage = res.nextPage
|
||||
const prevPage = res.prevPage
|
||||
const title = 'Шлиссельбургская ДХШ'
|
||||
|
||||
return {
|
||||
articles,
|
||||
nextPage,
|
||||
prevPage,
|
||||
pageUrl,
|
||||
title,
|
||||
meta: meta({
|
||||
props: {
|
||||
articles,
|
||||
nextPage,
|
||||
prevPage,
|
||||
pageUrl,
|
||||
title,
|
||||
url: pageUrl,
|
||||
})
|
||||
meta: meta({
|
||||
title,
|
||||
url: pageUrl,
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export default Page
|
||||
export default Page
|
||||
@@ -1,50 +0,0 @@
|
||||
import React from 'react'
|
||||
import Head from 'next/head'
|
||||
|
||||
import { App } from '../src/components/App'
|
||||
import { Page } from '../src/components/Page'
|
||||
import menuModel from '../src/models/menu'
|
||||
import { buildMenu } from '../src/lib/menu'
|
||||
import { Meta } from '../src/components/Meta'
|
||||
import { meta } from '../src/lib/meta'
|
||||
import { createApiUrl, requestGet, wrapInitialProps } from '../src/next-lib'
|
||||
|
||||
const Index = props => (
|
||||
<App
|
||||
menu={buildMenu(props.pageUrl, menuModel)}
|
||||
showAuthor={true}
|
||||
menuPadding={true}
|
||||
layout={'thin'}
|
||||
>
|
||||
<Head>
|
||||
<title>{props.title}</title>
|
||||
<Meta meta={props.meta} />
|
||||
</Head>
|
||||
|
||||
<Page
|
||||
showSocialShare={true}
|
||||
>
|
||||
{props.content}
|
||||
</Page>
|
||||
</App>
|
||||
)
|
||||
|
||||
Index.getInitialProps = wrapInitialProps(async (ctx) => {
|
||||
const pageUrl = ctx.req.url
|
||||
const page = await requestGet(createApiUrl(ctx.req, `/api/page?page=${pageUrl}`), {})
|
||||
const image = page.preview ? page.preview.artifacts.fb : {}
|
||||
|
||||
return {
|
||||
content: page.data,
|
||||
pageUrl,
|
||||
title: page.title,
|
||||
meta: meta({
|
||||
title: page.title,
|
||||
image: image.src,
|
||||
imageWidth: image.width,
|
||||
imageHeight: image.height,
|
||||
}),
|
||||
}
|
||||
})
|
||||
|
||||
export default Index
|
||||
@@ -1,42 +0,0 @@
|
||||
import React from 'react'
|
||||
import Head from 'next/head'
|
||||
import { App } from '../src/components/App'
|
||||
import { Schedule } from '../src/components/Schedule'
|
||||
import { Share } from '../src/components/Share'
|
||||
import menuModel from '../src/models/menu'
|
||||
import { buildMenu } from '../src/lib/menu'
|
||||
import { createApiUrl, requestGet, wrapInitialProps } from '../src/next-lib'
|
||||
|
||||
const Page = (props) => (
|
||||
<App
|
||||
menu={buildMenu(props.pageUrl, menuModel)}
|
||||
showAuthor={true}
|
||||
menuPadding={true}
|
||||
layout={'wide'}
|
||||
>
|
||||
<Head>
|
||||
<title>{props.title}</title>
|
||||
</Head>
|
||||
|
||||
{/*<ScheduleList schedules={schedules}/>*/}
|
||||
|
||||
<Schedule {...props.schedule} />
|
||||
|
||||
<Share />
|
||||
</App>
|
||||
)
|
||||
|
||||
Page.getInitialProps = wrapInitialProps(async (ctx) => {
|
||||
const pageUrl = ctx.req.url
|
||||
const period = '2016-2017'
|
||||
const semester = 'spring'
|
||||
const schedule = await requestGet(createApiUrl(ctx.req, `/api/schedule?period=${period}&semester=${semester}`), {})
|
||||
|
||||
return {
|
||||
schedule,
|
||||
pageUrl,
|
||||
title: 'Расписание',
|
||||
}
|
||||
})
|
||||
|
||||
export default Page
|
||||
@@ -0,0 +1,54 @@
|
||||
import Head from 'next/head'
|
||||
import { App } from 'src/components/App'
|
||||
import { Schedule } from 'src/components/Schedule'
|
||||
import { Share } from 'src/components/Share'
|
||||
import menuModel from 'src/models/menu'
|
||||
import { buildMenu } from 'src/lib/menu'
|
||||
import { createApiUrl, requestGet } from 'src/next-lib'
|
||||
import { NextPage } from 'next'
|
||||
|
||||
type Props = {
|
||||
pageUrl: string
|
||||
title: string
|
||||
data: any //(schedule)
|
||||
}
|
||||
|
||||
const Page: NextPage<Props> = props => (
|
||||
<App
|
||||
menu={buildMenu(props.pageUrl, menuModel)}
|
||||
showAuthor={true}
|
||||
menuPadding={true}
|
||||
layout={'wide'}
|
||||
>
|
||||
<Head>
|
||||
<title>{props.title}</title>
|
||||
</Head>
|
||||
|
||||
{/*<ScheduleList schedules={schedules}/>*/}
|
||||
|
||||
<Schedule {...props.data} />
|
||||
|
||||
<Share />
|
||||
</App>
|
||||
)
|
||||
|
||||
export const unstable_getStaticProps = async (ctx: any) => {
|
||||
// const pageUrl = ctx.req.url
|
||||
const pageUrl = '/schedule'
|
||||
const period = '2016-2017'
|
||||
const semester = 'spring'
|
||||
const data = await requestGet(createApiUrl(`/api/schedule?period=${period}&semester=${semester}`), null)
|
||||
if (!data) {
|
||||
return null
|
||||
}
|
||||
|
||||
return {
|
||||
props: {
|
||||
data,
|
||||
pageUrl,
|
||||
title: 'Расписание',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Page
|
||||
+88
-47
@@ -1,15 +1,14 @@
|
||||
import React from 'react'
|
||||
import Head from 'next/head'
|
||||
import { App } from '../../src/components/App'
|
||||
import Article from '../../src/components/Article'
|
||||
import { Meta } from '../../src/components/Meta'
|
||||
import menuModel from '../../src/models/menu'
|
||||
import { buildMenu } from '../../src/lib/menu'
|
||||
import { meta } from '../../src/lib/meta'
|
||||
import { createApiUrl, requestGet, wrapInitialProps } from '../../src/next-lib'
|
||||
import { NextPage } from 'next'
|
||||
import { IMeta } from '../../src/types'
|
||||
import Html from '../../src/components/Html'
|
||||
import { App } from 'src/components/App'
|
||||
import Article from 'src/components/Article'
|
||||
import { Meta } from 'src/components/Meta'
|
||||
import menuModel from 'src/models/menu'
|
||||
import { buildMenu } from 'src/lib/menu'
|
||||
import { meta } from 'src/lib/meta'
|
||||
import { createApiUrl, requestGet, IResponseItems } from 'src/next-lib'
|
||||
import { NextPage, NextPageContext } from 'next'
|
||||
import { IMeta } from 'src/types'
|
||||
import { Html } from 'src/components/Html'
|
||||
|
||||
interface IProps {
|
||||
pageUrl: string
|
||||
@@ -18,50 +17,92 @@ interface IProps {
|
||||
person: any
|
||||
}
|
||||
|
||||
const Index: NextPage<IProps> = props => (
|
||||
<App
|
||||
menu={buildMenu(props.pageUrl, menuModel)}
|
||||
showAuthor={true}
|
||||
menuPadding={true}
|
||||
layout={'thin'}
|
||||
>
|
||||
<Head>
|
||||
<title>{props.title}</title>
|
||||
<Meta meta={props.meta} />
|
||||
</Head>
|
||||
const Index: NextPage<IProps> = props => {
|
||||
if (!props?.person?.post) {
|
||||
console.log('kek error', props)
|
||||
|
||||
<Article
|
||||
title={''}
|
||||
tags={[]}
|
||||
date={null}
|
||||
shareable={true}
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<App
|
||||
menu={buildMenu(props.pageUrl, menuModel)}
|
||||
showAuthor={true}
|
||||
menuPadding={true}
|
||||
layout={'thin'}
|
||||
>
|
||||
<Html
|
||||
html={props.person.post}
|
||||
/>
|
||||
</Article>
|
||||
</App>
|
||||
)
|
||||
<Head>
|
||||
<title>{props.title}</title>
|
||||
<Meta meta={props.meta} />
|
||||
</Head>
|
||||
|
||||
{!props.person.post ? null : (
|
||||
<Article
|
||||
title={''}
|
||||
tags={[]}
|
||||
date={null}
|
||||
shareable={true}
|
||||
>
|
||||
<Html
|
||||
html={props.person.post}
|
||||
/>
|
||||
</Article>
|
||||
)}
|
||||
</App>
|
||||
)
|
||||
}
|
||||
|
||||
export const unstable_getStaticProps = async (ctx: any) => {
|
||||
console.log('call unstable_getStaticProps', ctx)
|
||||
|
||||
Index.getInitialProps = wrapInitialProps(async (ctx) => {
|
||||
const pageUrl = '/collective'
|
||||
const id = ctx.query.person
|
||||
const person: any = await requestGet(createApiUrl(ctx.req, `/api/persons/${id}`), {})
|
||||
// const id = ctx.query.person
|
||||
// const id = ctx.params.person ?? 'va-sarzhin'
|
||||
const id = ctx.params.person //?? 'mg-timasheva'
|
||||
|
||||
if (!id) {
|
||||
throw new Error('sry')
|
||||
}
|
||||
|
||||
const person = await requestGet<any>(createApiUrl(`/api/persons/${id}`), null)
|
||||
const name = person.name || []
|
||||
const title = name.join(' ')
|
||||
const image = person.preview ? person.preview.artifacts.fb : {}
|
||||
|
||||
return {
|
||||
pageUrl,
|
||||
person,
|
||||
title,
|
||||
meta: meta({
|
||||
title,
|
||||
image: image.src,
|
||||
imageWidth: image.width,
|
||||
imageHeight: image.height,
|
||||
})
|
||||
if (!person?.post) {
|
||||
throw new Error(`post kek ${id}`)
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
props: {
|
||||
pageUrl,
|
||||
person,
|
||||
title,
|
||||
meta: meta({
|
||||
title,
|
||||
image: image.src,
|
||||
imageWidth: image.width,
|
||||
imageHeight: image.height,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const unstable_getStaticPaths = async () => {
|
||||
console.log('call unstable_getStaticPaths')
|
||||
|
||||
const urls = await requestGet<IResponseItems<string>>(createApiUrl(`/api/persons/urls`), null)
|
||||
// const urls = {items: ['/teacher/va-sarzhin']}
|
||||
|
||||
return {
|
||||
paths: urls.items
|
||||
.map(x => x.replace('/teacher/', ''))
|
||||
.map(person => ({
|
||||
params: {
|
||||
person,
|
||||
},
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
export default Index
|
||||
+1
-1
@@ -3,7 +3,7 @@ const axios = require('axios')
|
||||
const fs = require('fs').promises
|
||||
|
||||
const api = axios.create({
|
||||
baseURL: 'http://localhost:3000',
|
||||
baseURL: 'https://api.tmshv.com/hudozka',
|
||||
})
|
||||
|
||||
async function getArticles(pageSize) {
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ const homeUrl = 'https://art.shlisselburg.org'
|
||||
const sitemapCacheTime = 600000
|
||||
|
||||
const api = axios.create({
|
||||
baseURL: 'http://localhost:3000',
|
||||
baseURL: 'https://api.tmshv.com/hudozka',
|
||||
})
|
||||
|
||||
async function getMenuUrls(frequency = 'daily') {
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"noEmitOnError": false,
|
||||
"target": "es5",
|
||||
"module": "commonjs",
|
||||
"jsx": "preserve",
|
||||
"outDir": "./build",
|
||||
"strict": false,
|
||||
"esModuleInterop": true
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts"
|
||||
]
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
import ImageArtifactType from '../core/ImageArtifactType'
|
||||
|
||||
const sizes = [
|
||||
ImageArtifactType.MEDIUM,
|
||||
ImageArtifactType.BIG,
|
||||
ImageArtifactType.ORIGIN,
|
||||
]
|
||||
|
||||
export function encodeFilePreview(file, sizes) {
|
||||
const preview = file.preview
|
||||
if (!preview) return null
|
||||
|
||||
const image = preview.findArtifact(sizes)
|
||||
if (!image) return null
|
||||
|
||||
return image.url
|
||||
}
|
||||
|
||||
export function encodeFile(file) {
|
||||
const imageUrl = encodeFilePreview(file, sizes)
|
||||
const category = (file.category || '')
|
||||
.replace('Documents/', '')
|
||||
.replace('Pages/', '')
|
||||
.replace('Albums/', '')
|
||||
.replace('Articles /', '')
|
||||
|
||||
return {
|
||||
imageUrl,
|
||||
category,
|
||||
title: file.title,
|
||||
fileName: file.fileInfo.name,
|
||||
fileSize: file.fileInfo.size,
|
||||
fileUrl: file.url,
|
||||
url: file.viewUrl,
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
import ImageArtifactType from '../core/ImageArtifactType'
|
||||
|
||||
export function encodeImage(image) {
|
||||
const artifacts = [
|
||||
ImageArtifactType.SMALL,
|
||||
ImageArtifactType.MEDIUM,
|
||||
ImageArtifactType.BIG,
|
||||
ImageArtifactType.LARGE,
|
||||
ImageArtifactType.ORIGIN,
|
||||
ImageArtifactType.ORIGINAL,
|
||||
ImageArtifactType.FACEBOOK = 'fb'
|
||||
].reduce((acc, size) => {
|
||||
return {
|
||||
...acc,
|
||||
[size]: image.getPicture(size),
|
||||
}
|
||||
}, {})
|
||||
|
||||
return {
|
||||
artifacts,
|
||||
hash: image.hash,
|
||||
file: image.file,
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
import { encodeImage } from './image'
|
||||
|
||||
export function encodePage(page) {
|
||||
return {
|
||||
id: page.id,
|
||||
title: page.title,
|
||||
url: page.url,
|
||||
data: page.data,
|
||||
preview: encodeImage(page.preview),
|
||||
tokens: page.tokens,
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
import ImageArtifactType from '../core/ImageArtifactType'
|
||||
import { encodeImage } from './image'
|
||||
const profilePicture = profile => profile.picture.getPicture(ImageArtifactType.BIG)
|
||||
|
||||
export function encodePerson(person) {
|
||||
return {
|
||||
...person,
|
||||
shortName: person.shortName(),
|
||||
name: person.splitName(),
|
||||
picture: profilePicture(person),
|
||||
preview: encodeImage(person.picture),
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,13 @@
|
||||
import React from 'react'
|
||||
import Paginator from './Paginator'
|
||||
import { ArticleCard } from './ArticleCard'
|
||||
|
||||
export const ArticleCardList = ({ articles, nextPage, prevPage }) => (
|
||||
export interface IArticleCardListProps {
|
||||
articles: any[]
|
||||
nextPage: number | null
|
||||
prevPage: number | null
|
||||
}
|
||||
|
||||
export const ArticleCardList:React.FC<IArticleCardListProps> = ({ articles, nextPage, prevPage }) => (
|
||||
<div>
|
||||
<style jsx>{`
|
||||
.body {
|
||||
@@ -1,7 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
export default function Html(props) {
|
||||
return (
|
||||
<div dangerouslySetInnerHTML={{ __html: props.html }} />
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
export type HtmlProps = {
|
||||
html: string
|
||||
}
|
||||
|
||||
export const Html: React.FC<HtmlProps> = props => (
|
||||
<div dangerouslySetInnerHTML={{ __html: props.html }} />
|
||||
)
|
||||
@@ -17,10 +17,6 @@ export const Overlay: React.FC<IOverlayProps> = props => {
|
||||
}
|
||||
}, [props.onClickOverlay])
|
||||
|
||||
React.useEffect(() => {
|
||||
document.body.classList.toggle('noscroll', props.show)
|
||||
}, [props.show])
|
||||
|
||||
return (
|
||||
<Transition
|
||||
duration={duration}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import * as React from 'react'
|
||||
import { Share } from '../Share'
|
||||
import Html from '../Html'
|
||||
import { Html } from '../Html'
|
||||
|
||||
export interface IPageProps {
|
||||
showSocialShare: boolean
|
||||
children: string
|
||||
}
|
||||
|
||||
export const Page: React.FC<IPageProps> = props => (
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import React from 'react'
|
||||
|
||||
const { getDates } = require('../utils/date')
|
||||
const { shortName } = require('../models/collective')
|
||||
import { getDates } from 'src/utils/date'
|
||||
import { shortName } from 'src/models/collective'
|
||||
|
||||
const now = new Date()
|
||||
const dates = getDates(now)
|
||||
@@ -1,22 +0,0 @@
|
||||
import path from 'path'
|
||||
|
||||
export const port = process.env['PORT'] || 3000
|
||||
|
||||
export const name = 'Hudozka'
|
||||
export const host = 'art.shlisselburg.org'
|
||||
export const protocol = 'https://'
|
||||
export const homeUrl = protocol + host
|
||||
|
||||
export const index = path.join(__dirname, 'templates/main.html')
|
||||
export const sitemapCacheTime = 600000// 600 sec - cache purge period
|
||||
|
||||
export const viewMain = path.join(__dirname, 'views/main.hbs')
|
||||
export const view404 = path.join(__dirname, 'views/404.hbs')
|
||||
|
||||
export const sessionConfig = {
|
||||
key: 'sid', /** (string) cookie key */
|
||||
maxAge: 86400000, /** (number) maxAge in ms */
|
||||
overwrite: false, /** (boolean) can overwrite or not */
|
||||
httpOnly: false, /** (boolean) httpOnly or not */
|
||||
signed: true, /** (boolean) signed or not */
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
import Data from './Data'
|
||||
import Image from './Image'
|
||||
import ImageArtifactType from './ImageArtifactType'
|
||||
import { find, findOne } from '../lib/store'
|
||||
|
||||
const previewTypes = [
|
||||
ImageArtifactType.SMALL,
|
||||
ImageArtifactType.MEDIUM,
|
||||
ImageArtifactType.BIG,
|
||||
ImageArtifactType.ORIGIN,
|
||||
]
|
||||
const store = () => Data.getStore('Album')
|
||||
|
||||
export default class Album {
|
||||
static async find(query, options = {}) {
|
||||
const items = await find(store(), query, options as any)
|
||||
|
||||
return Promise.all(items.map(processAlbum))
|
||||
}
|
||||
|
||||
static async findById(id) {
|
||||
const item = await findOne(store(), { id })
|
||||
|
||||
return !item
|
||||
? null
|
||||
: processAlbum(item)
|
||||
}
|
||||
}
|
||||
|
||||
const previewFromImage = (imgs = []) => imgs.length
|
||||
? imgs[0]
|
||||
: null
|
||||
|
||||
const processAlbum = async album => {
|
||||
let preview = {}
|
||||
// {
|
||||
// data: [
|
||||
// {
|
||||
// url: null,
|
||||
// width: 0,
|
||||
// height: 0,
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
|
||||
const previewImageId = album.preview ? album.preview : previewFromImage(album.images)
|
||||
if (previewImageId) {
|
||||
const image = await Image.findById(previewImageId)
|
||||
if (image) {
|
||||
// const imageArtifacts = image.findArtifact(previewTypes)
|
||||
// if (imageArtifacts) {
|
||||
// preview = imageArtifacts
|
||||
// }
|
||||
preview = image.getPicture(ImageArtifactType.SMALL)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
...album,
|
||||
preview,
|
||||
url: `/album/${album.id}`,
|
||||
}
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
import Data from './Data'
|
||||
import Image from './Image'
|
||||
import Config from './Config'
|
||||
import { find, findOne, total } from '../lib/store'
|
||||
|
||||
const store = () => Data.getStore<Article>('Article')
|
||||
|
||||
function make(C) {
|
||||
return x => new C(x)
|
||||
}
|
||||
|
||||
export default class Article {
|
||||
static async find(query, options = {}): Promise<Article[]> {
|
||||
const items = await find(store(), query, options as any)
|
||||
|
||||
return Promise.all(items.map(processArticle))
|
||||
}
|
||||
|
||||
static async findById(id) {
|
||||
const item = await findOne(store(), { id })
|
||||
|
||||
return !item
|
||||
? null
|
||||
: processArticle(item)
|
||||
}
|
||||
|
||||
static async total(query = {}) {
|
||||
return total(store(), query)
|
||||
}
|
||||
|
||||
static async findPinned() {
|
||||
const now = new Date()
|
||||
const query = { until: { $gte: now } }
|
||||
|
||||
return Article.find(query, {
|
||||
sort: { date: -1 },
|
||||
})
|
||||
}
|
||||
|
||||
public id: any
|
||||
public images: any
|
||||
public post: any
|
||||
public folder: any
|
||||
public date: any
|
||||
public title: any
|
||||
public until: any
|
||||
public tags: any
|
||||
public content: any
|
||||
public hash: any
|
||||
public type: any
|
||||
public origin: any
|
||||
public file: any
|
||||
public version: any
|
||||
public preview: any
|
||||
public url: any
|
||||
|
||||
constructor(data) {
|
||||
this.id = data.id
|
||||
this.images = data.images
|
||||
this.post = data.post
|
||||
this.folder = data.folder
|
||||
this.date = data.date
|
||||
this.title = data.title
|
||||
this.until = data.until
|
||||
this.tags = (data.tags || []).map(make(Tag))
|
||||
this.content = data.content
|
||||
this.hash = data.hash
|
||||
this.type = data.type
|
||||
this.origin = data.origin
|
||||
this.file = data.file
|
||||
this.version = data.version
|
||||
this.preview = data.preview
|
||||
|
||||
this.url = `/article/${this.id}`
|
||||
}
|
||||
|
||||
plain() {
|
||||
return {
|
||||
id: this.id,
|
||||
images: this.images,
|
||||
post: this.post,
|
||||
folder: this.folder,
|
||||
date: this.date,
|
||||
title: this.title,
|
||||
until: this.until,
|
||||
tags: this.tags,
|
||||
content: this.content,
|
||||
hash: this.hash,
|
||||
type: this.type,
|
||||
origin: this.origin,
|
||||
file: this.file,
|
||||
version: this.version,
|
||||
preview: this.preview,
|
||||
url: this.url,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Tag {
|
||||
public name: string
|
||||
|
||||
constructor(tag) {
|
||||
this.name = tag;
|
||||
}
|
||||
}
|
||||
|
||||
const previewFromImage = (imgs = []) => imgs.length
|
||||
? imgs[0]
|
||||
: null
|
||||
|
||||
async function resolveDefaultPreview() {
|
||||
const config = await Config.findConfig()
|
||||
if (!config) return null
|
||||
|
||||
return Image.findByFile(config.articleCardDefaultPreview)
|
||||
}
|
||||
|
||||
async function processArticle(article) {
|
||||
let preview = null
|
||||
const previewId = article.preview
|
||||
? article.preview
|
||||
: previewFromImage(article.images)
|
||||
|
||||
if (previewId) {
|
||||
preview = await Image.findById(previewId)
|
||||
} else {
|
||||
preview = await resolveDefaultPreview()
|
||||
}
|
||||
|
||||
return new Article({
|
||||
...article,
|
||||
preview,
|
||||
})
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
import Data from './Data'
|
||||
import { findOne } from '../lib/store'
|
||||
|
||||
const store = () => Data.getStore('Settings')
|
||||
|
||||
export default class Config {
|
||||
static async findConfig() {
|
||||
const config = await Config.findById('settings')
|
||||
return config || new Config({} as any)
|
||||
}
|
||||
|
||||
static async findById(id: string) {
|
||||
const data = await findOne(store(), { id })
|
||||
if (!data) return null
|
||||
|
||||
return new Config(data)
|
||||
}
|
||||
|
||||
public hash: any
|
||||
public file: any
|
||||
public server: any
|
||||
public articlesPerPage: any
|
||||
public collectiveOrder: any
|
||||
public articleCardDefaultPreview: any
|
||||
public collectiveImage: any
|
||||
public redirect: any
|
||||
|
||||
constructor({ hash, file, ...data }) {
|
||||
this.hash = hash
|
||||
this.file = file
|
||||
this.server = data.server
|
||||
this.articlesPerPage = data.articlesPerPage || 5
|
||||
this.collectiveOrder = data.collectiveOrder || []
|
||||
this.articleCardDefaultPreview = data.articleCardDefaultPreview
|
||||
this.collectiveImage = data.collectiveImage
|
||||
|
||||
const redirect = data.redirect || {}
|
||||
this.redirect = new Map(Object
|
||||
.entries(redirect)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import { Collection } from 'mongodb'
|
||||
import * as db from './db'
|
||||
|
||||
const store = new Map<string, Collection>()
|
||||
|
||||
export default class Data {
|
||||
static setStore(key: string, collection: Collection) {
|
||||
store.set(key, collection)
|
||||
}
|
||||
|
||||
static getStore<T>(key: string): Collection<T> {
|
||||
return store.get(key)
|
||||
}
|
||||
|
||||
static getCollection(name: string): Collection {
|
||||
return db.collection(name)
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
import Data from './Data'
|
||||
import Image from './Image'
|
||||
import { find, findOne } from '../lib/store'
|
||||
|
||||
const store = () => Data.getStore('Document')
|
||||
|
||||
export default class Document {
|
||||
static async find(query, options = {}) {
|
||||
const items = await find(store(), query, options as any)
|
||||
|
||||
return Promise.all(items.map(processDocument))
|
||||
}
|
||||
|
||||
static async findById(id) {
|
||||
const data = await findOne(store(), { id })
|
||||
if (!data) return null
|
||||
|
||||
return processDocument(data)
|
||||
}
|
||||
|
||||
public id: any
|
||||
public hash: any
|
||||
public file: any
|
||||
public fileInfo: any
|
||||
public type: any
|
||||
public title: any
|
||||
public category: any
|
||||
public url: any
|
||||
public preview: any
|
||||
public viewUrl: any
|
||||
|
||||
constructor(data) {
|
||||
this.id = data.id
|
||||
this.hash = data.hash
|
||||
this.file = data.file
|
||||
// In the future: use fileInfo only
|
||||
this.fileInfo = data.fileInfo
|
||||
? new DocumentFile(data.fileInfo)
|
||||
: 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 {
|
||||
public name: any
|
||||
public size: any
|
||||
|
||||
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,
|
||||
})
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
import Data from './Data'
|
||||
import ImageArtifactType from './ImageArtifactType'
|
||||
import { findOne } from '../lib/store'
|
||||
import { mapOf } from '../server/lib'
|
||||
|
||||
const store = () => Data.getStore('Image')
|
||||
|
||||
export default class Image {
|
||||
static async findById(id) {
|
||||
const data = await findOne(store(), { _id: id })
|
||||
if (!data) return null
|
||||
|
||||
const artifacts = data.data
|
||||
return new Image({ ...data, artifacts })
|
||||
}
|
||||
|
||||
static async findByFile(file: string) {
|
||||
const data = await findOne(store(), { file })
|
||||
if (!data) return null
|
||||
|
||||
const artifacts = data.data
|
||||
return new Image({ ...data, artifacts })
|
||||
}
|
||||
public hash: any
|
||||
public file: any
|
||||
public artifacts: any
|
||||
|
||||
constructor({ hash, file, artifacts }) {
|
||||
this.hash = hash
|
||||
this.file = file
|
||||
|
||||
this.artifacts = mapOf(ImageArtifact, artifacts)
|
||||
}
|
||||
|
||||
getArtifact(size) {
|
||||
return this.artifacts.get(size)
|
||||
}
|
||||
|
||||
findArtifact(sizes) {
|
||||
for (let size of sizes) {
|
||||
const a = this.getArtifact(size)
|
||||
if (a) return a
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
getPicture(size) {
|
||||
const retinaSize = ImageArtifactType.retina(size)
|
||||
|
||||
const a = this.getArtifact(size)
|
||||
const a2 = this.getArtifact(retinaSize)
|
||||
const srcset = !a2
|
||||
? []
|
||||
: [{
|
||||
url: a2.url,
|
||||
density: ImageArtifactType.RETINA_DENSITY,
|
||||
}]
|
||||
|
||||
return {
|
||||
src: a.url,
|
||||
width: a.width,
|
||||
height: a.height,
|
||||
set: srcset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ImageArtifact {
|
||||
public url: any
|
||||
public size: any
|
||||
public width: any
|
||||
public height: any
|
||||
|
||||
constructor({ url, size, width, height }) {
|
||||
this.url = url
|
||||
this.size = size
|
||||
this.width = width
|
||||
this.height = height
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
import Data from './Data'
|
||||
import { find as storeFind, findOne, total } from '../lib/store'
|
||||
import Image from './Image'
|
||||
import Config from './Config'
|
||||
|
||||
const store = () => Data.getStore('Page')
|
||||
|
||||
export default class Page {
|
||||
static async find(query, options = {}): Promise<Page[]> {
|
||||
const items = await storeFind(store(), query, options as any)
|
||||
|
||||
return Promise.all(items.map(processPage))
|
||||
}
|
||||
|
||||
static async findById(id) {
|
||||
const item = await findOne(store(), { id })
|
||||
|
||||
return !item
|
||||
? null
|
||||
: processPage(item)
|
||||
}
|
||||
|
||||
static async findByUrl(url) {
|
||||
const item = await findOne(store(), { url })
|
||||
|
||||
return !item
|
||||
? null
|
||||
: processPage(item)
|
||||
}
|
||||
|
||||
static async total(query = {}) {
|
||||
return total(store(), query)
|
||||
}
|
||||
|
||||
public id: any
|
||||
public hash: any
|
||||
public file: any
|
||||
public url: string
|
||||
public content: any
|
||||
public title: any
|
||||
public data: any
|
||||
public images: any
|
||||
public documents: any
|
||||
public preview: any
|
||||
public tokens: any[]
|
||||
|
||||
constructor(data) {
|
||||
this.id = data.id
|
||||
this.hash = data.hash
|
||||
this.file = data.file
|
||||
this.url = data.url
|
||||
this.content = data.content
|
||||
this.title = data.title
|
||||
this.data = data.data
|
||||
this.images = data.images
|
||||
this.documents = data.documents
|
||||
this.preview = data.preview
|
||||
this.tokens = data.tokens
|
||||
}
|
||||
|
||||
plain() {
|
||||
return {
|
||||
id: this.id,
|
||||
images: this.images,
|
||||
documents: this.documents,
|
||||
data: this.data,
|
||||
title: this.title,
|
||||
content: this.content,
|
||||
hash: this.hash,
|
||||
file: this.file,
|
||||
preview: this.preview,
|
||||
url: this.url,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const previewFromImage = (imgs = []) => imgs.length
|
||||
? imgs[0]
|
||||
: null
|
||||
|
||||
async function resolveDefaultPreview() {
|
||||
const config = await Config.findConfig()
|
||||
if (!config) return null
|
||||
|
||||
return Image.findByFile(config.articleCardDefaultPreview)
|
||||
}
|
||||
|
||||
async function processPage(article) {
|
||||
let preview = null
|
||||
const previewId = article.preview
|
||||
? article.preview
|
||||
: previewFromImage(article.images)
|
||||
|
||||
if (previewId) {
|
||||
preview = await Image.findById(previewId)
|
||||
} else {
|
||||
preview = await resolveDefaultPreview()
|
||||
}
|
||||
|
||||
return new Page({
|
||||
...article,
|
||||
preview,
|
||||
})
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
import Data from './Data'
|
||||
import Image from './Image'
|
||||
import { find, findOne } from '../lib/store'
|
||||
|
||||
const store = () => Data.getStore('Teacher')
|
||||
|
||||
export default class Teacher {
|
||||
static async find(query, options = {}) {
|
||||
const items = await find(store(), query, options as any)
|
||||
|
||||
return Promise.all(items.map(processProfile))
|
||||
}
|
||||
|
||||
static async findById(id) {
|
||||
const data = await findOne(store(), { id })
|
||||
if (!data) return null
|
||||
|
||||
return processProfile(data)
|
||||
}
|
||||
|
||||
public id: any
|
||||
public post: any
|
||||
public file: any
|
||||
public edu: any
|
||||
public picture: any
|
||||
public preview: any
|
||||
public diploma: any
|
||||
public position: any
|
||||
public name: any
|
||||
public status: any
|
||||
public hash: any
|
||||
public url: any
|
||||
|
||||
constructor(data) {
|
||||
this.id = data.id
|
||||
this.post = data.post
|
||||
this.file = data.file
|
||||
this.edu = data.edu
|
||||
this.picture = data.picture
|
||||
this.preview = data.preview
|
||||
this.diploma = data.diploma
|
||||
this.position = data.position
|
||||
this.name = data.name
|
||||
this.status = data.status
|
||||
this.hash = data.hash
|
||||
|
||||
this.url = `/teacher/${this.id}`
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* "First Middle Last" -> "F. M. Last"
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
shortName() {
|
||||
const f = i => i.replace(/^(.).+/, '$1')
|
||||
const [first, middle, last] = this.splitName()
|
||||
|
||||
return `${f(first)}. ${f(middle)}. ${last}`
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* "First Middle Last" -> ["First", "Middle", "Last"]
|
||||
*
|
||||
* @returns {Array|{index: number, input: string}}
|
||||
*/
|
||||
splitName() {
|
||||
const name = this.name
|
||||
const m = /(.+)\s(.+)\s(.+)/.exec(name)
|
||||
return m.slice(1)
|
||||
}
|
||||
}
|
||||
|
||||
const processProfile = async profile => {
|
||||
const imageId = profile.picture
|
||||
const previewId = profile.preview
|
||||
const picture = await Image.findById(imageId)
|
||||
const preview = await Image.findById(previewId)
|
||||
|
||||
return new Teacher({
|
||||
...profile,
|
||||
picture,
|
||||
preview,
|
||||
})
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
import Data from './Data'
|
||||
import Page from './Page'
|
||||
import Article from './Article'
|
||||
const Album = require('./Album')
|
||||
const Teacher = require('./Teacher')
|
||||
const Document = require('./Document')
|
||||
const Image = require('./Image')
|
||||
import Settings from './Config'
|
||||
const getConfig = require('next/config').default
|
||||
|
||||
const { MongoClient, ObjectId } = require('mongodb')
|
||||
|
||||
var db
|
||||
|
||||
export async function connect() {
|
||||
if (db) {
|
||||
return db
|
||||
}
|
||||
const mongoUri = getConfig().serverRuntimeConfig.dbUri
|
||||
const connection = await MongoClient.connect(mongoUri)
|
||||
db = init(connection)
|
||||
return db
|
||||
}
|
||||
|
||||
export function collection(name) {
|
||||
return db.collection(name)
|
||||
}
|
||||
|
||||
export function id(i) {
|
||||
if (typeof i === 'string') return ObjectId(i)
|
||||
else if (i instanceof ObjectId) return i
|
||||
else if (i instanceof Object) return '_id' in i ? ObjectId(i._id) : null
|
||||
return null
|
||||
}
|
||||
|
||||
function init(db) {
|
||||
console.log('INIT DB')
|
||||
|
||||
Data.setStore('Page', db.collection('pages'))
|
||||
Data.setStore('Article', db.collection('articles'))
|
||||
Data.setStore('Album', db.collection('albums'))
|
||||
Data.setStore('Image', db.collection('images'))
|
||||
Data.setStore('Teacher', db.collection('collective'))
|
||||
Data.setStore('Document', db.collection('documents'))
|
||||
Data.setStore('Settings', db.collection('settings'))
|
||||
|
||||
return db
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
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});
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* @param redirectMap
|
||||
* [{String url, String redirect}, ...]
|
||||
* @returns {*}
|
||||
*/
|
||||
function redirect(redirectMap) {
|
||||
return async (ctx, next) => {
|
||||
const path = ctx.request.path
|
||||
|
||||
if (redirectMap.has(path)) {
|
||||
const url = redirectMap.get(path)
|
||||
ctx.redirect(url)
|
||||
} else {
|
||||
await next()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = redirect
|
||||
@@ -1,20 +0,0 @@
|
||||
// import { MongoClient } from 'mongodb';
|
||||
// const { connect, collection } = require('../../src/core/db')
|
||||
import {collection, connect} from '../core/db'
|
||||
|
||||
// const client = new MongoClient(process.env.MONGODB_URI, { useNewUrlParser: true });
|
||||
|
||||
export const withCollection = handler => async (req, res) => {
|
||||
await connect()
|
||||
|
||||
req.collection = collection
|
||||
|
||||
// if (!client.isConnected()) {
|
||||
// return client.connect().then(() => {
|
||||
// req.db = client.db('nextjsmongodbapp');
|
||||
// return handler(req, res);
|
||||
// });
|
||||
// }
|
||||
// req.db = client.db('nextjsmongodbapp');
|
||||
return handler(req, res)
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
import { withCollection } from './withCollection'
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
|
||||
export type Handler = (req: NextApiRequest, res: NextApiResponse) => void
|
||||
|
||||
export const withMiddleware = (handler: Handler) => withCollection(handler)
|
||||
@@ -1,22 +0,0 @@
|
||||
const courses = {
|
||||
painting: ['Живопись', ''],
|
||||
drawing: ['Рисунок', '/courses/drawing'],
|
||||
sculpting: ['Скульптура', ''],
|
||||
sculpture: ['Скульптура', ''],
|
||||
ceramic: ['Керамика', '/courses/ceramics'],
|
||||
ceramics: ['Керамика', '/courses/ceramics'],
|
||||
composition: ['Композиция', ''],
|
||||
'easel-composition': ['Станковая композиция', ''],
|
||||
dpi: ['ДПИ', ''],
|
||||
'art-talks': ['Беседа по искусству', ''],
|
||||
history: ['История искусства', '/courses/art-history'],
|
||||
cg: ['Комп. графика', '/courses/cg'],
|
||||
}
|
||||
|
||||
export function getCourse(id) {
|
||||
const course = id in courses ? courses[id] : null
|
||||
if (!course) return null
|
||||
|
||||
const [title, url] = course
|
||||
return {id, title, url}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
export const autumnMonth = 8;
|
||||
export const springMonth = 0;
|
||||
|
||||
export function scheduleDate(schedule){
|
||||
let {period, semester} = schedule;
|
||||
|
||||
let i = semester === 'spring' ? 1 : 0;
|
||||
let year = getPeriod(period)[i];
|
||||
|
||||
return new Date(
|
||||
year,
|
||||
i ? springMonth : autumnMonth,
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* f("2012-2015") -> [2012, 2015]
|
||||
* f(["2012", "2015"]) -> [2012, 2015]
|
||||
* f([2012, 2015]) -> [2012, 2015]
|
||||
*
|
||||
* @param i
|
||||
* @returns {*}
|
||||
*/
|
||||
export function getPeriod(i){
|
||||
if (typeof i === 'string') return getPeriod(i.split('-'));
|
||||
|
||||
return i.map(Number);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* f("2012-2015") -> "2012-2015"
|
||||
* f(["2012", "2015"]) -> "2012-2015"
|
||||
* f([2012, 2015]) -> "2012-2015"
|
||||
*
|
||||
* @param i
|
||||
* @returns {*}
|
||||
*/
|
||||
export function getPeriodString(i) {
|
||||
return getPeriod(i)
|
||||
.join('-')
|
||||
}
|
||||
+2
-23
@@ -31,27 +31,6 @@ export function wrapInitialProps(fn: (ctx: NextPageContext) => void) {
|
||||
}
|
||||
}
|
||||
|
||||
export function createApiUrl(req, path) {
|
||||
const { origin } = absoluteUrl(req, 'localhost:3000')
|
||||
|
||||
return `${origin}${path}`
|
||||
}
|
||||
|
||||
function absoluteUrl(req, defaultLocalhost) {
|
||||
let protocol = 'https:'
|
||||
let host = req
|
||||
? (req.headers['x-forwarded-host'] || req.headers['host'])
|
||||
: window.location.host
|
||||
host = host || defaultLocalhost
|
||||
if (host.indexOf('localhost') > -1) {
|
||||
if (defaultLocalhost) host = defaultLocalhost
|
||||
protocol = 'http:'
|
||||
}
|
||||
const origin = protocol + '//' + host
|
||||
|
||||
return {
|
||||
protocol,
|
||||
host,
|
||||
origin,
|
||||
}
|
||||
export function createApiUrl(path: string) {
|
||||
return `https://api.tmshv.com/hudozka${path}`
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
import Koa from 'koa'
|
||||
import next from 'next'
|
||||
import { get } from 'koa-route'
|
||||
import { connect } from './core/db'
|
||||
import Page from './core/Page'
|
||||
|
||||
const dev = process.env.NODE_ENV !== 'production'
|
||||
const app = next({ dev })
|
||||
const handle = app.getRequestHandler()
|
||||
const port = parseInt(process.env.PORT, 10) || 3000
|
||||
|
||||
app.prepare().then(async () => {
|
||||
try {
|
||||
await connect()
|
||||
} catch (e) {
|
||||
console.error(e.message)
|
||||
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const pages = await Page.find({})
|
||||
const pagesUrls = pages.map(x => x.url)
|
||||
|
||||
const server = new Koa()
|
||||
server.use(async (ctx, next) => {
|
||||
ctx.res.statusCode = 200
|
||||
await next()
|
||||
})
|
||||
|
||||
server.use(get('*', async ctx => {
|
||||
const url = ctx.req.url
|
||||
|
||||
if (pagesUrls.includes(url)) {
|
||||
await app.render(ctx.req, ctx.res, '/next', ctx.query)
|
||||
} else {
|
||||
await handle(ctx.req, ctx.res)
|
||||
}
|
||||
|
||||
ctx.respond = false
|
||||
}))
|
||||
|
||||
server.listen(port, () => {
|
||||
console.log(`> Ready on http://localhost:${port}`)
|
||||
})
|
||||
})
|
||||
@@ -1,71 +0,0 @@
|
||||
import Article from '../core/Article'
|
||||
import ImageArtifactType from '../core/ImageArtifactType'
|
||||
import { sortBy } from '../utils/sort'
|
||||
import { timestamp } from '../lib/date'
|
||||
import { encodeImage } from '../api/image'
|
||||
|
||||
export const sortArticleByDate = sortBy(
|
||||
x => timestamp(new Date(x.date))
|
||||
)
|
||||
|
||||
export async function findArticlesNin(nin, skip, limit, sort) {
|
||||
const query = {
|
||||
_id: { $nin: nin }
|
||||
}
|
||||
|
||||
return Article.find(query, {
|
||||
sort,
|
||||
skip,
|
||||
limit,
|
||||
})
|
||||
}
|
||||
|
||||
export async function findArticles(page: number, pageSize: number) {
|
||||
const limit = pageSize
|
||||
const skip = (page - 1) * pageSize
|
||||
|
||||
const pinnedArticles = page === 1
|
||||
? await Article.findPinned()
|
||||
: []
|
||||
|
||||
const total = await Article.total()
|
||||
const totalPages = Math.ceil(total / pageSize)
|
||||
|
||||
const id = i => i._id
|
||||
const pinnedIds = pinnedArticles.map(id)
|
||||
const articles = await findArticlesNin(pinnedIds, skip, limit, { date: -1 })
|
||||
|
||||
const prevPage = page > 1
|
||||
? page - 1
|
||||
: null
|
||||
|
||||
const nextPage = page < totalPages
|
||||
? page + 1
|
||||
: null
|
||||
|
||||
const items = [
|
||||
...pinnedArticles.sort(sortArticleByDate),
|
||||
...articles
|
||||
]
|
||||
.map(x => x.plain())
|
||||
.map(x => ({
|
||||
...x,
|
||||
preview: !x.preview ? null : (
|
||||
x.preview.getPicture(ImageArtifactType.MEDIUM)
|
||||
)
|
||||
}))
|
||||
|
||||
return {
|
||||
items,
|
||||
prevPage,
|
||||
nextPage,
|
||||
totalPages,
|
||||
}
|
||||
}
|
||||
|
||||
export function encodeArticle(article) {
|
||||
return {
|
||||
...article,
|
||||
preview: encodeImage(article.preview),
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
const { collection } = require('../core/db')
|
||||
// import { collection } from '../core/db'
|
||||
|
||||
export async function getCollective(query = {}) {
|
||||
return await collection('collective')
|
||||
.find(query)
|
||||
.toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a person by it's id
|
||||
*
|
||||
* @param id
|
||||
* @returns {Promise|*}
|
||||
*/
|
||||
export async function getPerson(id) {
|
||||
return await collection('collective').findOne({ id: id });
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* {a: {}, b: {}, ...} -> Map (a: Class, b: Class)
|
||||
*
|
||||
* @param Class
|
||||
* @param object
|
||||
*/
|
||||
export function mapOf(Class, object) {
|
||||
return Object
|
||||
.entries(object)
|
||||
.reduce((map, i) => (
|
||||
map.set(i[0], new Class(i[1]))
|
||||
), new Map())
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
// import {collection} from '../core/db'
|
||||
// const {collection} = require('../core/db')
|
||||
import {createMap} from '../utils/common'
|
||||
import {getCollective} from './collective'
|
||||
|
||||
import {scheduleDate, getPeriod as schedulePeriod, getPeriodString} from '../models/schedule'
|
||||
import {getCourse} from '../models/course'
|
||||
|
||||
const last = require('../lib/array').last
|
||||
const sortBy = require('../lib/sort').sortBy
|
||||
|
||||
const SCHEDULES = 'schedules'
|
||||
|
||||
export async function findSchedule(collection, period, semester) {
|
||||
const schedule = await collection(SCHEDULES).findOne({
|
||||
$or: [
|
||||
{period: period},
|
||||
{period: schedulePeriod(period)}
|
||||
],
|
||||
semester: semester
|
||||
})
|
||||
|
||||
return schedule ? migrate(schedule) : null
|
||||
}
|
||||
|
||||
async function findAllScheduleParams() {
|
||||
const schedules = await collection(SCHEDULES)
|
||||
.find({}, {
|
||||
period: 1,
|
||||
semester: 1,
|
||||
_id: 0,
|
||||
})
|
||||
.toArray()
|
||||
|
||||
return schedules
|
||||
.map(i => ({
|
||||
...i,
|
||||
period: schedulePeriod(i.period),
|
||||
}))
|
||||
.sort(sortBy(
|
||||
i => scheduleDate(i).getTime(),
|
||||
true,
|
||||
))
|
||||
}
|
||||
|
||||
async function findDefaultScheduleParams() {
|
||||
const schedules = await findAllScheduleParams()
|
||||
return last(schedules
|
||||
.map(i => ({
|
||||
...i,
|
||||
period: getPeriodString(i.period),
|
||||
}))
|
||||
)
|
||||
}
|
||||
|
||||
function text({semester, period}) {
|
||||
const word = semester => [['spring', 'Весна'], ['autumn', 'Осень']]
|
||||
.find(i => i[0] === semester)
|
||||
[1]
|
||||
const periodIndex = semester === 'spring' ? 1 : 0
|
||||
const year = period[periodIndex]
|
||||
|
||||
return `${word(semester)} ${year} года`
|
||||
}
|
||||
|
||||
async function migrate(schedule) {
|
||||
const versions = {
|
||||
'1.0': migrate10to20,
|
||||
'2.0': migrate20to30,
|
||||
}
|
||||
|
||||
const version = schedule.version
|
||||
const update = versions[version]
|
||||
return version in versions ? migrate(update(schedule)) : schedule
|
||||
}
|
||||
|
||||
function migrate10to20(schedule) {
|
||||
const dayNames = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']
|
||||
const time = time => time
|
||||
.map(i => i.split(' '))
|
||||
|
||||
const week = days => days.reduce((week, lesson, index) => {
|
||||
if (lesson) {
|
||||
const day = dayNames[index]
|
||||
week[day] = [Object.assign(lesson, {
|
||||
time: time(lesson.time)
|
||||
})]
|
||||
}
|
||||
|
||||
return week
|
||||
}, {})
|
||||
|
||||
return Object.assign(schedule, {
|
||||
version: '2.0',
|
||||
period: schedulePeriod(schedule.period),
|
||||
groups: schedule.schedule
|
||||
.map(group => ({
|
||||
name: group.group,
|
||||
time: group.time,
|
||||
week: week(group.week)
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
async function migrate20to30(schedule) {
|
||||
const days = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat']//, 'sun']
|
||||
|
||||
const persons = await getCollective()
|
||||
const person = createMap(i => i.id, persons)
|
||||
|
||||
const week = week => days
|
||||
.map(day => week[day] || [])
|
||||
.map(lessons => lessons.map(lesson))
|
||||
|
||||
const lesson = i => ({
|
||||
time: i.time,
|
||||
course: getCourse(i.lesson),
|
||||
teacher: person.has(i.teacher) ? teacher(i.teacher) : teacherDummy(i.teacher)
|
||||
})
|
||||
|
||||
const teacher = id => ({
|
||||
id: id,
|
||||
url: `/teacher/${id}`,
|
||||
name: personName(id)
|
||||
})
|
||||
|
||||
const teacherDummy = name => ({
|
||||
id: name,
|
||||
url: null,
|
||||
name: name
|
||||
})
|
||||
|
||||
const personName = id => person.has(id) ? person.get(id).name : null
|
||||
|
||||
return Object.assign(schedule, {
|
||||
version: '3.0',
|
||||
groups: schedule.groups
|
||||
.map(group => ({
|
||||
name: group.name,
|
||||
time: group.time,
|
||||
week: week(group.week)
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
// exports.findSchedule = findSchedule
|
||||
// exports.findAllScheduleParams = findAllScheduleParams
|
||||
// exports.findDefaultScheduleParams = findDefaultScheduleParams
|
||||
// exports.text = text
|
||||
@@ -1,8 +1,7 @@
|
||||
:root {
|
||||
//SHADOW
|
||||
--white-shadow: 0 0.1em 0.3em rgba(0, 0, 0, 0.2);
|
||||
|
||||
//FONTS
|
||||
/* FONTS */
|
||||
--title-font: Shadow, 'PT Serif', Georgia, serif;
|
||||
--text-font: 'PT Sans', Arial, sans-serif;
|
||||
|
||||
@@ -12,15 +11,12 @@
|
||||
--big-font-size: 1.5rem;
|
||||
--biggest-font-size: 2.25rem;
|
||||
|
||||
//MENU
|
||||
/* MENU */
|
||||
--menu-thickness: 2.5em;
|
||||
--menu-colored-mark-thickness: 4px;
|
||||
--menu-inactive-item-color: hsl(0, 0%, 50%);
|
||||
|
||||
//ANIMATION
|
||||
$short-duration: 0.3s;
|
||||
|
||||
//SIZE
|
||||
/* SIZE */
|
||||
--mobile-width: 31.25em;
|
||||
--desktop-width: 59.99999em;
|
||||
|
||||
@@ -37,7 +33,7 @@
|
||||
--text-color: #303030;
|
||||
--text-color-second: #ccc;
|
||||
|
||||
//FONTS
|
||||
/* FONTS */
|
||||
--font-size-default: 14pt;
|
||||
--font-size-second: 0.9rem;
|
||||
|
||||
@@ -45,7 +41,7 @@
|
||||
--font-size-h2: 2.5rem;
|
||||
--font-size-h3: 1.5rem;
|
||||
|
||||
//COLOR
|
||||
/* COLOR */
|
||||
--dark-color: hsl(0, 0%, 20%);
|
||||
--darker-color: hsl(0, 0%, 10%);
|
||||
--light-color: hsl(0, 0%, 80%);
|
||||
@@ -65,13 +61,76 @@
|
||||
|
||||
--schedule-row-color: hsl(210, 55%, 90%);
|
||||
|
||||
//MARGINS
|
||||
/* MARGINS */
|
||||
--small-margin: 0.2em;
|
||||
--half-margin: 0.5em;
|
||||
--single-margin: 1em;
|
||||
--double-margin: 2em;
|
||||
--post-margin: 5em;
|
||||
|
||||
//OTHER
|
||||
/* OTHER */
|
||||
--block-border-radius: 3px;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
min-width: 320px;
|
||||
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
font-size: var(--font-size-h1);
|
||||
|
||||
hyphens: none;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin: var(--single-margin) 0;
|
||||
font-size: var(--font-size-h2);
|
||||
|
||||
hyphens: none;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin: var(--single-margin) 0;
|
||||
|
||||
font-size: var(--font-size-h3);
|
||||
|
||||
hyphens: none;
|
||||
}
|
||||
|
||||
.actor {
|
||||
border-bottom: 1px dashed black;
|
||||
}
|
||||
|
||||
.actor:hover {
|
||||
border-bottom: 2px solid black;
|
||||
}
|
||||
|
||||
@media (max-width: 31.25em) {
|
||||
:root {
|
||||
--smaller-font-size: 0.9rem;
|
||||
--normal-font-size: 1rem;
|
||||
--bigger-font-size: 1.1rem;
|
||||
--big-font-size: 1.3rem;
|
||||
--biggest-font-size: 2rem;
|
||||
|
||||
--font-size-h1: 1.5rem;
|
||||
--font-size-h2: 1.5rem;
|
||||
--font-size-h3: 1.25rem;
|
||||
|
||||
--content-thin: 90%;
|
||||
--content-wide: 90%;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
@import "variables";
|
||||
|
||||
.album-block {
|
||||
//margin: 1em auto 2em;
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
@import "../variables";
|
||||
|
||||
.ArticleTags {
|
||||
--article-card-width: 30%;
|
||||
--article-card-margin: var(--single-margin) var(--half-margin);
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
.page-collective {
|
||||
&.ng-leave {
|
||||
animation: slideOutLeft var(--short-duration) both ease-in;
|
||||
}
|
||||
|
||||
&.ng-enter {
|
||||
animation: slideInRight var(--short-duration) both ease-in;
|
||||
}
|
||||
}
|
||||
|
||||
.page-collective {
|
||||
&__collective-image {
|
||||
//min-height: 40em;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: var(--mobile-width)) {
|
||||
.page-collective {
|
||||
&__collective-image {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
.page-schedule {
|
||||
&.ng-leave {
|
||||
transform-origin: 0% 0%;
|
||||
animation: rotateFall var(--short-duration) both ease-in;
|
||||
}
|
||||
|
||||
&.ng-enter {
|
||||
animation: scaleUp var(--short-duration) both ease-in;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
@import "../variables";
|
||||
|
||||
.parallax {
|
||||
min-width: 1280px;
|
||||
width: 1280px;
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
@import "../variables";
|
||||
|
||||
$user-size: 40px;
|
||||
$half-margin: $single-margin/2;
|
||||
$image-border-radius: .35em;
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
@import "variables";
|
||||
|
||||
footer {
|
||||
padding: 0 var(--half-margin) var(--half-margin);
|
||||
position: relative;
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
min-width: 320px;
|
||||
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
font-size: var(--font-size-h1);
|
||||
|
||||
hyphens: none;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin: var(--single-margin) 0;
|
||||
font-size: var(--font-size-h2);
|
||||
|
||||
hyphens: none;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin: var(--single-margin) 0;
|
||||
|
||||
font-size: var(--font-size-h3);
|
||||
|
||||
hyphens: none;
|
||||
}
|
||||
|
||||
.actor {
|
||||
border-bottom: 1px dashed black;
|
||||
|
||||
&:hover {
|
||||
border-bottom: 2px solid black;
|
||||
}
|
||||
}
|
||||
@@ -15,12 +15,8 @@
|
||||
@import "components/album";
|
||||
@import "components/parallax";
|
||||
|
||||
@import "components/page-schedule";
|
||||
@import "components/page-collective";
|
||||
|
||||
@import "components/ArticleTags";
|
||||
|
||||
@import "main";
|
||||
@import "body-wrapper";
|
||||
@import "content";
|
||||
@import "page-animation";
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
@import "variables";
|
||||
|
||||
.vertical-image {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
||||
@@ -1,20 +1,3 @@
|
||||
/**
|
||||
* Generates list of numbers
|
||||
* @param {Number} start starting value
|
||||
* @param {Number} num amount of numbers in list
|
||||
* @param {Number} step difference value
|
||||
* @return {Array} list of numbers
|
||||
*/
|
||||
export function range(start, num, step) {
|
||||
var list = [];
|
||||
var val = start;
|
||||
for (var i = 0; i < num; i++) {
|
||||
list.push(val);
|
||||
val += step;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a closure that compares a Number argument with specified Number
|
||||
* @param withNumber Number to compare with
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
import {range} from './common';
|
||||
import { range } from 'lodash'
|
||||
|
||||
/**
|
||||
*
|
||||
* @param start
|
||||
* @returns {*}
|
||||
*/
|
||||
export function getDates(start) {
|
||||
export function getDates(start: Date) {
|
||||
const oneDay = (1000 * 60 * 60 * 24);
|
||||
const startTime = start.getTime();
|
||||
const startDay = start.getDay();
|
||||
|
||||
return range(0, 6, 1)
|
||||
return range(0, 6)
|
||||
.reduce((dates, weekDay) => {
|
||||
let delta = 1 + weekDay - startDay;
|
||||
let time = startTime + (oneDay * delta);
|
||||
@@ -18,4 +13,4 @@ export function getDates(start) {
|
||||
return dates.concat([new Date(time)]);
|
||||
}, [])
|
||||
.map(i => i.getDate());
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
import {getPeriod} from '../../src/models/schedule';
|
||||
|
||||
describe('models', () => {
|
||||
describe('schedule.js', () => {
|
||||
describe('getPeriod', () => {
|
||||
it('should accept a string and return an array', () => {
|
||||
getPeriod('2016-2017').should.be.Array;
|
||||
});
|
||||
|
||||
it('should accept a string "XXXX-YYYY" and return an array [XXXX, YYYY]', () => {
|
||||
const sample = '2016-2017';
|
||||
const result = getPeriod(sample);
|
||||
result.should.be.eql([2016, 2017]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"target": "es5",
|
||||
"lib": [
|
||||
"dom",
|
||||
|
||||
Reference in new issue
Block a user