add blog
This commit is contained in:
1 parent
36338ed0d7
commit
7fe8f5d154
96 files changed
+21326
No files matched your search
@@ -0,0 +1,403 @@
|
||||
<template lang="pug">
|
||||
div(style="width: 100vw; height: 100vh")
|
||||
#global
|
||||
.reveal
|
||||
.slides
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Vue, Component } from 'nuxt-property-decorator'
|
||||
import MakeHtml from '@/assets/make-html'
|
||||
import matter from 'gray-matter'
|
||||
import { apiHash } from '@/assets/util'
|
||||
// @ts-ignore
|
||||
import shortHash from 'short-hash'
|
||||
import $ from 'cheerio'
|
||||
// @ts-ignore
|
||||
import scopeCss from 'scope-css'
|
||||
import h from 'hyperscript'
|
||||
import qs from 'querystring'
|
||||
import stringify from 'fast-json-stable-stringify'
|
||||
import { globalStore } from '../store'
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
Reveal: RevealStatic
|
||||
hljs: any
|
||||
revealMd: RevealMd
|
||||
}
|
||||
}
|
||||
|
||||
export interface ISlide {
|
||||
id: string
|
||||
type: 'hidden' | 'global' | 'regular'
|
||||
html: string
|
||||
raw: string
|
||||
}
|
||||
|
||||
const revealCdn = 'https://cdn.jsdelivr.net/npm/reveal.js@3.8.0/'
|
||||
const makeHtml = new MakeHtml()
|
||||
|
||||
@Component({
|
||||
layout: 'full',
|
||||
watchQuery: ['path'],
|
||||
})
|
||||
export default class RevealMd extends Vue {
|
||||
trueHeader: any = {}
|
||||
trueMarkdown = ''
|
||||
queue: Array<(r?: RevealStatic) => void> = []
|
||||
raw: ISlide[][] = [[]]
|
||||
|
||||
title = ''
|
||||
defaults = {
|
||||
header: {},
|
||||
markdown: '',
|
||||
}
|
||||
|
||||
isReady = false
|
||||
|
||||
async asyncData ({ $axios, query }: any) {
|
||||
const { path } = query
|
||||
|
||||
if (path) {
|
||||
try {
|
||||
const raw = await apiHash(`/build/slides/${path}`, globalStore.hash.slides[path as string])
|
||||
const { data, content } = matter(raw)
|
||||
|
||||
return {
|
||||
defaults: {
|
||||
header: data,
|
||||
markdown: content,
|
||||
},
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
return {}
|
||||
}
|
||||
|
||||
head () {
|
||||
return {
|
||||
title: this.title,
|
||||
link: [
|
||||
{
|
||||
rel: 'stylesheet',
|
||||
href: `${revealCdn}css/reveal.css`,
|
||||
type: 'text/css',
|
||||
},
|
||||
{
|
||||
rel: 'stylesheet',
|
||||
href: `${revealCdn}css/theme/white.css`,
|
||||
type: 'text/css',
|
||||
id: 'reveal-theme',
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
async mounted () {
|
||||
let currentSlide = ''
|
||||
|
||||
if (process.client) {
|
||||
window.revealMd = this
|
||||
|
||||
const { path } = this.$route.query
|
||||
if (!this.defaults.markdown && path) {
|
||||
try {
|
||||
const raw = await apiHash(`/build/slides/${path}`, globalStore.hash.slides[path as string])
|
||||
const { data, content } = matter(raw)
|
||||
|
||||
this.defaults.markdown = content
|
||||
this.defaults.header = data
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
this.markdown = this.defaults.markdown
|
||||
this.header = this.defaults.header
|
||||
this.onReady(() => {
|
||||
if (currentSlide) {
|
||||
location.hash = currentSlide
|
||||
}
|
||||
})
|
||||
|
||||
currentSlide = location.hash.replace(/^#/, '')
|
||||
const script = document.createElement('script')
|
||||
script.onload = () => {
|
||||
window.Reveal.initialize({
|
||||
slideNumber: true,
|
||||
// @ts-ignore
|
||||
hash: true,
|
||||
dependencies: [
|
||||
{
|
||||
src: `${revealCdn}plugin/highlight/highlight.js`,
|
||||
async: true,
|
||||
},
|
||||
],
|
||||
})
|
||||
window.Reveal.addEventListener('ready', () => {
|
||||
this.isReady = true
|
||||
})
|
||||
}
|
||||
script.src = `${revealCdn}js/reveal.min.js`
|
||||
document.body.appendChild(script)
|
||||
}
|
||||
}
|
||||
|
||||
get header (): RevealOptions & {
|
||||
theme?: string
|
||||
title?: string
|
||||
} {
|
||||
return this.trueHeader || {}
|
||||
}
|
||||
|
||||
set header (h) {
|
||||
const { theme, title, ...subH } = h
|
||||
|
||||
this.theme = theme || 'white'
|
||||
this.title = title || ''
|
||||
|
||||
if (stringify(this.trueHeader) === stringify(subH)) {
|
||||
return
|
||||
}
|
||||
|
||||
this.onReady(() => {
|
||||
window.Reveal.configure(subH)
|
||||
})
|
||||
|
||||
this.trueHeader = subH
|
||||
}
|
||||
|
||||
get markdown () {
|
||||
return this.trueMarkdown
|
||||
}
|
||||
|
||||
set markdown (s: string) {
|
||||
this.trueMarkdown = s
|
||||
|
||||
const globalEl = this.$el.querySelector('#global') as HTMLElement
|
||||
Array.from(globalEl.querySelectorAll('style.ref')).map((el) => el.remove())
|
||||
|
||||
let xOffset = 0
|
||||
const newRaw = s.split(/\r?\n(?:===|---)\r?\n/g).map((el, x) => {
|
||||
this.raw[x] = this.raw[x] || []
|
||||
const newRawSs = el.split(/\r?\n--\r?\n/g).map((ss) => this.parseSlide(ss))
|
||||
if (newRawSs.every((ss) => !ss.html)) {
|
||||
xOffset++
|
||||
}
|
||||
|
||||
x -= xOffset
|
||||
|
||||
let yOffset = 0
|
||||
return newRawSs.map((thisRaw, y) => {
|
||||
if (!thisRaw.html) {
|
||||
yOffset++
|
||||
return
|
||||
}
|
||||
|
||||
y -= yOffset
|
||||
|
||||
let section = this.getSlide(x)
|
||||
let subSection = this.getSlide(x, y)
|
||||
|
||||
if (!this.raw[x][y] || (this.raw[x][y] && this.raw[x][y].raw !== thisRaw.raw)) {
|
||||
const container = document.createElement('div')
|
||||
container.className = 'container'
|
||||
container.innerHTML = thisRaw.html
|
||||
|
||||
if (section && subSection) {
|
||||
const oldContainers = subSection.getElementsByClassName('container')
|
||||
Array.from(oldContainers).forEach((el) => el.remove())
|
||||
subSection.appendChild(container)
|
||||
} else {
|
||||
subSection = document.createElement('section')
|
||||
subSection.append(container)
|
||||
|
||||
if (section) {
|
||||
section.appendChild(subSection)
|
||||
} else {
|
||||
section = document.createElement('section')
|
||||
section.appendChild(subSection)
|
||||
this.$el.querySelector('.reveal .slides')!.appendChild(section)
|
||||
}
|
||||
}
|
||||
|
||||
Array.from(container.querySelectorAll('pre code:not(.hljs)')).forEach((el) => {
|
||||
if (window.hljs) {
|
||||
window.hljs.highlightBlock(el)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return thisRaw
|
||||
}).filter((el) => el)
|
||||
}).filter((el) => el && el.length > 0) as ISlide[][]
|
||||
|
||||
this.raw.map((el, x) => {
|
||||
el.map((ss, j) => {
|
||||
const y = el.length - j - 1
|
||||
|
||||
if (!newRaw[x] || !newRaw[x][y]) {
|
||||
const subSection = this.getSlide(x, y)
|
||||
if (subSection) {
|
||||
subSection.remove()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if (!newRaw[x]) {
|
||||
const section = this.getSlide(x)
|
||||
if (section) {
|
||||
section.remove()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
this.raw = newRaw
|
||||
}
|
||||
|
||||
get theme () {
|
||||
const el = document.getElementById('reveal-theme') as HTMLLinkElement
|
||||
const m = /\/(\S+)\.css$/.exec(el.href)
|
||||
if (m) {
|
||||
return m[1]
|
||||
}
|
||||
|
||||
return ''
|
||||
}
|
||||
|
||||
set theme (t) {
|
||||
const el = document.getElementById('reveal-theme') as HTMLLinkElement
|
||||
el.href = `${revealCdn}css/theme/${t}.css`
|
||||
}
|
||||
|
||||
update (raw: string) {
|
||||
const { data, content } = matter(raw)
|
||||
this.markdown = content
|
||||
this.header = data
|
||||
}
|
||||
|
||||
onReady (fn?: () => void) {
|
||||
if (this.isReady) {
|
||||
if (this.queue.length > 0) {
|
||||
this.queue.forEach(it => it())
|
||||
window.Reveal.slide(-1, -1, -1)
|
||||
window.Reveal.sync()
|
||||
}
|
||||
|
||||
if (fn) {
|
||||
fn()
|
||||
}
|
||||
} else {
|
||||
if (fn) {
|
||||
this.queue.push(fn)
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
this.onReady()
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
|
||||
parseSlide (text: string): ISlide {
|
||||
const id = shortHash(text)
|
||||
const raw = text
|
||||
let type: 'hidden' | 'global' | 'regular' = 'regular'
|
||||
let html = text
|
||||
const [firstLine, ...lines] = html.split('\n')
|
||||
const newType = firstLine.substr(3)
|
||||
if (newType === 'hidden') {
|
||||
type = 'hidden'
|
||||
return { html: '', raw, id, type }
|
||||
} else if (newType === 'global') {
|
||||
type = 'global'
|
||||
html = lines.join('\n')
|
||||
}
|
||||
|
||||
html = html.replace(/(?:^|\n)\/\/ css=([A-Za-z0-9\-_]+\.css)(?:$|\n)/g, (p0, ref: string) => {
|
||||
const i = raw.indexOf(p0)
|
||||
const globalEl = this.$el.querySelector('#global') as HTMLDivElement
|
||||
const className = `ref${i}`
|
||||
|
||||
let el = globalEl.querySelector(`style.ref.${className}`)
|
||||
if (!el) {
|
||||
el = document.createElement('style')
|
||||
el.classList.add('ref', className)
|
||||
globalEl.appendChild(el)
|
||||
}
|
||||
|
||||
let url = ref
|
||||
if (!ref.includes('://')) {
|
||||
url = `/api/data?${qs.stringify({
|
||||
filename: ref,
|
||||
})}`
|
||||
}
|
||||
|
||||
fetch(url).then((r) => r.text()).then((content) => {
|
||||
if (type !== 'global') {
|
||||
content = scopeCss(content, `#${id}`)
|
||||
}
|
||||
el!.innerHTML = content
|
||||
})
|
||||
|
||||
return ''
|
||||
})
|
||||
|
||||
html = html.replace(/(?:^|\n)(\/\/ slide\n)?```(\S+)\n([^]+?)\n```(?:$|\n)/g, (p0, subtype, lang, content) => {
|
||||
if (type !== 'global' && !subtype) {
|
||||
return p0
|
||||
}
|
||||
|
||||
if (lang === 'css') {
|
||||
const globalEl = this.$el.querySelector('#global') as HTMLDivElement
|
||||
if (type !== 'global') {
|
||||
content = scopeCss(content, `#${id}`)
|
||||
}
|
||||
let el = globalEl.querySelector('style.main')
|
||||
if (!el) {
|
||||
el = document.createElement('style')
|
||||
el.className = 'main'
|
||||
globalEl.appendChild(el)
|
||||
}
|
||||
el.innerHTML = content
|
||||
return ''
|
||||
} else if (lang === 'pre') {
|
||||
return h('pre', content).outerHTML
|
||||
// } else if (lang === 'pug') {
|
||||
// return makeHtml.pugConvert(content)
|
||||
} else if (lang === 'html') {
|
||||
return content
|
||||
}
|
||||
|
||||
return p0
|
||||
})
|
||||
|
||||
return {
|
||||
html: h(`#${id}`, {
|
||||
innerHTML: makeHtml.mdConvert(html),
|
||||
}).outerHTML,
|
||||
raw,
|
||||
id,
|
||||
type,
|
||||
}
|
||||
}
|
||||
|
||||
getSlide (x: number, y?: number) {
|
||||
const s = this.$el.querySelectorAll('.slides > section')
|
||||
const hSlide = s[x]
|
||||
|
||||
if (typeof y === 'number') {
|
||||
if (hSlide) {
|
||||
return Array.from(hSlide.children).filter((el) => el.tagName.toLocaleUpperCase() === 'SECTION')[y]
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
return hSlide
|
||||
}
|
||||
}
|
||||
</script>
|
||||
Reference in new issue
Block a user