Created
September 16, 2019 16:57
-
-
Save yue4u/e4103a1e32bba8b4693e2e27e1499ed8 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Server API makes it possible to hook into various parts of Gridsome | |
| // on server-side and add custom data to the GraphQL data layer. | |
| // Learn more: https://gridsome.org/docs/server-api | |
| // Changes here require a server restart. | |
| // To restart press CTRL + C in terminal and run `gridsome develop` | |
| const syllabus = require("../data/syllabus.json"); | |
| const search = require("../data/search.json"); | |
| const { createHash } = require("crypto") | |
| const nodeExternals = require('webpack-node-externals') | |
| const hash = (text) => { | |
| return createHash('md5').update(text).digest('hex').slice(0, 8) | |
| } | |
| const hashStore = {} | |
| const uniqueHash = (text) => { | |
| let hashString = ''; | |
| while (true) { | |
| hashString = hash(text) | |
| if (hashString in hashStore) { | |
| hashString = hash(hashString) | |
| } else { | |
| hashStore[text] = hashString | |
| hashStore[hashString] = text | |
| break; | |
| } | |
| } | |
| return hashString; | |
| } | |
| const upper = (text) => text.slice(0, 1).toUpperCase() + text.slice(1); | |
| module.exports = function (api) { | |
| api.chainWebpack((config, { isServer }) => { | |
| if (isServer) { | |
| config.externals([ | |
| nodeExternals({ | |
| whitelist: [/^vuetify/] | |
| }) | |
| ]) | |
| } | |
| }) | |
| api.loadSource(({ addContentType, createReference, addReference }) => { | |
| const subjectType = addContentType({ | |
| typeName: "Subject", | |
| route: "/subject/:id" | |
| }); | |
| const detailType = addContentType({ | |
| typeName: "Detail" | |
| }); | |
| const teacherType = addContentType({ | |
| typeName: "Teacher", | |
| route: "/teacher/:id" | |
| }); | |
| const categoryType = addContentType({ | |
| typeName: "Category", | |
| route: "/category/:id" | |
| }); | |
| const fieldType = addContentType({ | |
| typeName: "Field", | |
| route: "/field/:id" | |
| }); | |
| const yearType = addContentType({ | |
| typeName: "Year", | |
| route: "/year/:id" | |
| }); | |
| const teachers = {}; | |
| const categories = {}; | |
| const years = {}; | |
| const fields = {}; | |
| const gather = (collection, key, code) => { | |
| if (key in collection) { | |
| collection[key].subjects.push(code); | |
| } else { | |
| collection[key] = { | |
| subjects: [code] | |
| }; | |
| } | |
| }; | |
| const create = (contentTypeName, contentType, collection) => { | |
| Object.entries(collection).map(([key, val]) => { | |
| const hash = uniqueHash(`${contentTypeName}:${key}`) | |
| collection[key].id = hash; | |
| contentType.addNode({ | |
| id: hash, | |
| name: key || "不明", | |
| ...val, | |
| subjects: { | |
| totalCount: val.subjects.length, | |
| node: createReference("Subject", val.subjects) | |
| } | |
| }); | |
| }); | |
| }; | |
| syllabus.data.map(subject => { | |
| gather(teachers, subject.teacher, subject.code); | |
| gather(categories, subject.category, subject.code); | |
| gather(years, subject.year, subject.code); | |
| gather(fields, subject.field, subject.code); | |
| }); | |
| create('teacher', teacherType, teachers); | |
| create('category', categoryType, categories); | |
| create('year', yearType, years); | |
| create('field', fieldType, fields); | |
| syllabus.data.map(subject => { | |
| const detail = { ...subject.detail }; | |
| delete subject.detail; | |
| const detailNode = detailType.addNode({ | |
| ...detail, | |
| path: `subject/${subject.code}/detail` | |
| }); | |
| const subjectRef = Object.fromEntries( | |
| ['teacher', 'category', 'year', 'field'].map(typeName => { | |
| const hash = hashStore[`${typeName}:${subject[typeName]}`]; | |
| const typeNameUpper = upper(typeName); | |
| return [typeName, createReference(typeNameUpper, hash)] | |
| })) | |
| subjectType.addNode({ | |
| ...subject, | |
| ...subjectRef, | |
| id: subject.code, | |
| detail: createReference(detailNode), | |
| teacher: createReference("Teacher", teachers[subject.teacher].id), | |
| categories: createReference("Categoy", categories[subject.category].id), | |
| year: createReference("Year", years[subject.year].id) | |
| }); | |
| }); | |
| const emailType = addContentType({ | |
| typeName: "Email" | |
| }); | |
| const emailMap = {} | |
| search.data.map(item => { | |
| /** | |
| * @see https://stackoverflow.com/a/1373724 | |
| */ | |
| const emailMatched = [...item.text.matchAll( | |
| /([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+)/gi)].map(match => match[1]) | |
| const subject = syllabus.data.find(subject => item.id === subject.code) | |
| if (subject && emailMatched.length) { | |
| for (let email of emailMatched) { | |
| if (!Array.isArray(emailMap[subject.teacher])) { | |
| emailMap[subject.teacher] = [] | |
| } | |
| if (!emailMap[subject.teacher].includes(email)) { | |
| emailMap[subject.teacher].push({ | |
| link: email, | |
| subject: createReference('Subject', subject.code) | |
| }) | |
| } | |
| } | |
| } | |
| }) | |
| Object.entries(emailMap).map(([teacher, item]) => { | |
| const teacherID = hashStore[`teacher:${teacher}`]; | |
| emailType.addNode({ | |
| id: hash(`email:${teacher}`), | |
| teacher: createReference('Teacher', teacherID), | |
| addresses: item | |
| }); | |
| }) | |
| }); | |
| //api.createPages(({ createPage }) => { | |
| // Use the Pages API here: https://gridsome.org/docs/pages-api | |
| //}); | |
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // This is the main.js file. Import global CSS and scripts here. | |
| // The Client API can be used here. Learn more: gridsome.org/docs/client-api | |
| import DefaultLayout from "~/layouts/Default.vue"; | |
| import SyllabusButton from "~/components/SyllabusButton.vue"; | |
| import SyllabusList from "~/components/SyllabusList.vue"; | |
| import SyllabusStatistics from "~/components/SyllabusStatistics.vue"; | |
| import SyllabusSection from "~/components/SyllabusSection.vue"; | |
| import Vuetify from 'vuetify' | |
| import 'vuetify/dist/vuetify.min.css' | |
| export default function (Vue, { router, isClient, appOptions, head }) { | |
| Vue.component("syllabus-layout", DefaultLayout); | |
| Vue.component("syllabus-button", SyllabusButton); | |
| Vue.component("syllabus-list", SyllabusList); | |
| Vue.component("syllabus-statistics", SyllabusStatistics); | |
| Vue.component("syllabus-section", SyllabusSection); | |
| head.link.push({ | |
| rel: 'stylesheet', | |
| href: 'https://fonts.googleapis.com/icon?family=Material+Icons' | |
| }) | |
| Vue.use(Vuetify) | |
| appOptions.vuetify = new Vuetify(opts); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment