From 734fdca8094bafa6e576a2124fb050db5197ebc6 Mon Sep 17 00:00:00 2001 From: Ahad Birang Date: Mon, 12 Jul 2021 20:16:39 +0430 Subject: [PATCH] feat: change slot definition (#535) * feat: change slot definition * feat: front matter style data * chore: update docs * docs: fix docs * chore: refactor data tokenizer * fix: typo * fix: invalid line detection --- docs/content/1.get-started/1.installation.md | 1 + docs/content/2.writing/1.my-first-page.md | 5 +- docs/content/2.writing/2.syntax.md | 36 +++--- docs/content/2.writing/example-page.md | 5 +- docs/content/3.features/3.assets.md | 2 + docs/content/3.features/6.extend.md | 1 + docs/content/3.features/7.migration.md | 1 + docs/content/5.templates/1.pre-launch.md | 1 + docs/content/5.templates/2.pricing.md | 2 +- docs/content/index.md | 16 ++- .../micromark-directive/constants.ts | 4 + .../tokenize-directive-container.ts | 115 +++++++++++++++++- .../remark-directive/from-markdown.ts | 21 +++- src/core/runtime/utils.ts | 3 + 14 files changed, 184 insertions(+), 29 deletions(-) diff --git a/docs/content/1.get-started/1.installation.md b/docs/content/1.get-started/1.installation.md index 369074f6f..88a70e70d 100644 --- a/docs/content/1.get-started/1.installation.md +++ b/docs/content/1.get-started/1.installation.md @@ -76,6 +76,7 @@ Checkout the [Deployment](/features/deployment) section when you are ready to pu ## Demo ::video-player{loop playsinline controls} +--- sources: - src: https://res.cloudinary.com/nuxt/video/upload/q_auto/v1612886404/docus/docus-vercel_wwaryz.webm type: video/webm diff --git a/docs/content/2.writing/1.my-first-page.md b/docs/content/2.writing/1.my-first-page.md index e3bb6be03..100461fdd 100644 --- a/docs/content/2.writing/1.my-first-page.md +++ b/docs/content/2.writing/1.my-first-page.md @@ -42,6 +42,7 @@ Using our custom syntax, you can easily add and configure components into your p ... Front-matter 👆 ::block-hero +--- cta: - Get started - /get-started/installation @@ -51,10 +52,10 @@ secondary: snippet: npx degit nuxtlabs/docus-starter#main docs --- ----title +#title The next big thing ----description +#description The favorite package of your favorite package. :: ``` diff --git a/docs/content/2.writing/2.syntax.md b/docs/content/2.writing/2.syntax.md index 86832bbc8..827115b8f 100644 --- a/docs/content/2.writing/2.syntax.md +++ b/docs/content/2.writing/2.syntax.md @@ -54,6 +54,7 @@ There is a few things to know about it: // YAML Method ::card + --- icon: IconNuxt description: Harness the full power of Nuxt and the Nuxt ecosystem. iconClass: 'text-hex-00DC82' @@ -86,6 +87,7 @@ There is a few things to know about it: :: ::card + --- icon: IconNuxt description: Harness the full power of Nuxt and the Nuxt ecosystem. iconClass: 'text-hex-00DC82' @@ -162,13 +164,14 @@ There is a few things to know about it: ```md [Code] ::card + --- icon: IconNuxt title: A complex card. --- Default slot - ---description + #description ::alert Description slot :: @@ -189,13 +192,14 @@ There is a few things to know about it: ::code-block{label="Preview" preview} ::card + --- icon: IconNuxt title: A complex card. --- Default slot - ---description + #description ::alert Description slot :: @@ -209,13 +213,14 @@ There is a few things to know about it: ```md [Code] ::card - icon: IconNuxt - title: A complex card. + --- + icon: IconNuxt + title: A complex card. --- Default slot - ---description + #description ::alert Description slot :: @@ -224,13 +229,14 @@ There is a few things to know about it: ::code-block{label="Preview" preview} ::card - icon: IconNuxt - title: A complex card. + --- + icon: IconNuxt + title: A complex card. --- Default slot - ---description + #description ::alert Description slot :: @@ -244,13 +250,14 @@ There is a few things to know about it: ```md [Code] ::card - icon: IconNuxt - title: A complex card. + --- + icon: IconNuxt + title: A complex card. --- Default slot - ---description + #description :::alert Description slot ::: @@ -259,13 +266,14 @@ There is a few things to know about it: ::code-block{label="Preview" preview} ::card - icon: IconNuxt - title: A complex card. + --- + icon: IconNuxt + title: A complex card. --- Default slot - ---description + #description :::alert Description slot ::: diff --git a/docs/content/2.writing/example-page.md b/docs/content/2.writing/example-page.md index 5e1b6af7a..faa6ad4cd 100644 --- a/docs/content/2.writing/example-page.md +++ b/docs/content/2.writing/example-page.md @@ -7,6 +7,7 @@ layout: --- ::block-hero +--- cta: - Get started - /get-started/installation @@ -16,10 +17,10 @@ secondary: snippet: npx degit nuxtlabs/docus-starter#main docs --- ----title +#title The next big thing ----description +#description The favorite package of your favorite package. :: diff --git a/docs/content/3.features/3.assets.md b/docs/content/3.features/3.assets.md index 43025fd1e..6e0ce06e3 100644 --- a/docs/content/3.features/3.assets.md +++ b/docs/content/3.features/3.assets.md @@ -73,6 +73,7 @@ Docus includes a **Video Player** component. ```markdown [Markdown] ::video-player{loop playsinline controls} + --- sources: - src: https://res.cloudinary.com/nuxt/video/upload/q_auto/v1612886404/docus/docus-vercel_wwaryz.webm type: video/webm @@ -87,6 +88,7 @@ Docus includes a **Video Player** component. ::code-block{label="Preview"} ::video-player{loop playsinline controls} + --- sources: - src: https://res.cloudinary.com/nuxt/video/upload/q_auto/v1612886404/docus/docus-vercel_wwaryz.webm type: video/webm diff --git a/docs/content/3.features/6.extend.md b/docs/content/3.features/6.extend.md index ab6ad9bfa..0252e0015 100644 --- a/docs/content/3.features/6.extend.md +++ b/docs/content/3.features/6.extend.md @@ -43,6 +43,7 @@ export default { ``` ::alert +--- type: success --- That's it! Deploy your project and enjoy Plausible. diff --git a/docs/content/3.features/7.migration.md b/docs/content/3.features/7.migration.md index 06a31dd47..cab9fb5a9 100644 --- a/docs/content/3.features/7.migration.md +++ b/docs/content/3.features/7.migration.md @@ -148,6 +148,7 @@ You might also need to follow the migration guide from [WindiCSS](https://windic Visit [Configuration](/get-started/configuration) page to update your configuration files with Docus features. ::alert +--- type: success --- diff --git a/docs/content/5.templates/1.pre-launch.md b/docs/content/5.templates/1.pre-launch.md index 3dd2765bd..4d437ff98 100644 --- a/docs/content/5.templates/1.pre-launch.md +++ b/docs/content/5.templates/1.pre-launch.md @@ -10,6 +10,7 @@ layout: ::pre-launch-hero +--- title: Awesome startup description: Pretty long awesome startup description cta: diff --git a/docs/content/5.templates/2.pricing.md b/docs/content/5.templates/2.pricing.md index 9dbc79bf1..3ea48b30a 100644 --- a/docs/content/5.templates/2.pricing.md +++ b/docs/content/5.templates/2.pricing.md @@ -4,7 +4,7 @@ footer: false --- ::pricing-block - +--- plans: monthly: base: true diff --git a/docs/content/index.md b/docs/content/index.md index 046ac4ffe..1973925b2 100644 --- a/docs/content/index.md +++ b/docs/content/index.md @@ -11,6 +11,7 @@ layout.aside: true --- ::block-hero +--- cta: - Get started - /get-started/installation @@ -18,16 +19,17 @@ secondary: - Open on GitHub → - https://github.com/nuxtlabs/docus snippet: npx docus-init my-website - ----title +--- +#title The Jamstack Website Generator. ----description +#description Write pages in markdown, use [Vue](https://vuejs.org) components, add style with [Windi CSS](https://windicss.org/) and enjoy the power of [Nuxt](https://nuxtjs.org) with a blazing fast developer experience. :: ::card-grid{title="What's included?"} ::card + --- icon: IconNuxt description: Harness the full power of Nuxt and the Nuxt ecosystem. iconClass: 'text-hex-00DC82' @@ -36,6 +38,7 @@ Write pages in markdown, use [Vue](https://vuejs.org) components, add style with :: ::card + --- icon: IconVue title: Vue Components. description: Use built-in components (or your own!) inside your content. @@ -43,6 +46,7 @@ Write pages in markdown, use [Vue](https://vuejs.org) components, add style with :: ::card + --- icon: IconMarkdown title: Write Markdown. description: Enjoy the ease and simplicity of Markdown as you write your documentation. @@ -50,6 +54,7 @@ Write pages in markdown, use [Vue](https://vuejs.org) components, add style with :: ::card + --- icon: IconWindi title: Windi CSS. description: Windi CSS is built in for great developer experience and rapid customization. @@ -57,6 +62,7 @@ Write pages in markdown, use [Vue](https://vuejs.org) components, add style with :: ::card + --- icon: IconSSG title: Static Generation. description: Generate your documentation as a static website and host it anywhere. @@ -64,6 +70,7 @@ Write pages in markdown, use [Vue](https://vuejs.org) components, add style with :: ::card + --- icon: IconLighthouse title: Lighthouse Optimised. description: Start with a blazing fast site with a perfect Lighthouse score. @@ -71,6 +78,7 @@ Write pages in markdown, use [Vue](https://vuejs.org) components, add style with :: ::card + --- icon: IconZap title: Smart Generation. description: Automatically skip a full build if you've only changed Markdown files. @@ -78,6 +86,7 @@ Write pages in markdown, use [Vue](https://vuejs.org) components, add style with :: ::card + --- icon: IconPuzzle title: Extensible. description: Customize the whole design, or add components using slots - you can make Docus your own. @@ -85,6 +94,7 @@ Write pages in markdown, use [Vue](https://vuejs.org) components, add style with :: ::card + --- icon: IconGitHub title: Open Source. description: Docus is released under the MIT license and made with love by the NuxtLabs team. diff --git a/src/core/parser/markdown/directive/micromark-directive/constants.ts b/src/core/parser/markdown/directive/micromark-directive/constants.ts index 5d3ab4b4d..0398d6e2d 100644 --- a/src/core/parser/markdown/directive/micromark-directive/constants.ts +++ b/src/core/parser/markdown/directive/micromark-directive/constants.ts @@ -3,6 +3,10 @@ export const ContainerSequenceSize = 2 export const SectionSequenceSize = 3 export const Codes = { + /** + * '#' + */ + hash: 35, /** * '`' */ diff --git a/src/core/parser/markdown/directive/micromark-directive/tokenize-directive-container.ts b/src/core/parser/markdown/directive/micromark-directive/tokenize-directive-container.ts index 982aaa0d3..9f9bcde9c 100644 --- a/src/core/parser/markdown/directive/micromark-directive/tokenize-directive-container.ts +++ b/src/core/parser/markdown/directive/micromark-directive/tokenize-directive-container.ts @@ -1,4 +1,6 @@ import { Effects, Okay, NotOkay } from 'micromark/dist/shared-types' +import markdownSpace from 'micromark/dist/character/markdown-space' +import asciiAlpha from 'micromark/dist/character/ascii-alpha' import markdownLineEnding from 'micromark/dist/character/markdown-line-ending' import createSpace from 'micromark/dist/tokenize/factory-space' import sizeChunks from 'micromark/dist/util/size-chunks' @@ -10,6 +12,10 @@ import { Codes, ContainerSequenceSize, SectionSequenceSize } from './constants' const label: any = { tokenize: tokenizeLabel, partial: true } const attributes: any = { tokenize: tokenizeAttributes, partial: true } +// section sparator +const sectionSeparatorCode = Codes.hash +const sectionSeparatorLength = 1 + /** * Calculate line indention size, line indention could be consists of multiple `linePrefix` events * @param events parser tokens @@ -28,6 +34,12 @@ function linePrefixSize(events) { return size } +enum MarkDownDataSectionState { + NotSeen = 0, + Open = 1, + Closed = 2 +} + function tokenize(effects: Effects, ok: Okay, nok: NotOkay) { const self = this const initialPrefix = linePrefixSize(this.events) @@ -35,6 +47,11 @@ function tokenize(effects: Effects, ok: Okay, nok: NotOkay) { let previous const containerSequenceSize = [] + /** + * data tokenizer + */ + const data = tokenizeData.call(this, effects, lineStart) + return start function start(code: number) { @@ -60,19 +77,23 @@ function tokenize(effects: Effects, ok: Okay, nok: NotOkay) { } function closingSectionSequence(code: number) { - if (code === Codes.dash) { + if (code === sectionSeparatorCode) { effects.consume(code) size++ return closingSectionSequence } - if (size < SectionSequenceSize) return nok(code) + if (size !== sectionSeparatorLength) return nok(code) if (sectionIndentSize !== initialPrefix) return nok(code) + // non ascii chars are invalid + if (!asciiAlpha(code)) return nok(code) + effects.exit('directiveContainerSectionSequence') return createSpace(effects, ok, 'whitespace')(code) } } + function sectionOpen(code: number) { effects.enter('directiveContainerSection') @@ -147,6 +168,19 @@ function tokenize(effects: Effects, ok: Okay, nok: NotOkay) { } effects.enter('directiveContainerContent') + + if (!containerSequenceSize.length && !data.isClosed() && (code === Codes.dash || markdownSpace(code))) { + function _chunkStart(code) { + data.close() + effects.enter('directiveContainerSection') + + return lineStart(code) + } + return effects.attempt(data.tokenize, data.sectionOpen, _chunkStart) + } else { + data.close() + } + effects.enter('directiveContainerSection') return lineStart(code) } @@ -156,9 +190,14 @@ function tokenize(effects: Effects, ok: Okay, nok: NotOkay) { return after(code) } - if (!containerSequenceSize.length && (code === Codes.dash || code === Codes.space)) { + // detect slots + if (!containerSequenceSize.length && (code === sectionSeparatorCode || code === Codes.space)) { return effects.attempt({ tokenize: tokenizeSectionClosing, partial: true } as any, sectionOpen, chunkStart) } + // detect slots + if (!containerSequenceSize.length && !data.isClosed() && (code === Codes.dash || code === Codes.space)) { + return effects.attempt(data.tokenize, data.sectionOpen, chunkStart) + } const attempt = effects.attempt({ tokenize: tokenizeClosingFence, partial: true } as any, after, chunkStart) @@ -290,6 +329,76 @@ function tokenize(effects: Effects, ok: Okay, nok: NotOkay) { } } +function tokenizeData(effects, ok) { + const initialPrefix = linePrefixSize(this.events) + let sectionState: MarkDownDataSectionState = MarkDownDataSectionState.NotSeen + const data = { + state: () => sectionState, + close: () => { + sectionState = MarkDownDataSectionState.Closed + }, + isClosed: () => sectionState === MarkDownDataSectionState.Closed, + tokenize: { tokenize: tokenizeDataSection, partial: true } as any, + sectionOpen + } + return data + function tokenizeDataSection(effects: Effects, ok: Okay, nok: NotOkay) { + const self = this + let size = 0 + let sectionIndentSize = 0 + + return closingPrefixAfter + + function closingPrefixAfter(code: number) { + if (data.isClosed()) { + return nok(code) + } + if (markdownSpace(code)) { + effects.consume(code) + sectionIndentSize += 1 + return closingPrefixAfter + } + if (sectionIndentSize === 0) { + sectionIndentSize = linePrefixSize(self.events) + } + if (sectionState === MarkDownDataSectionState.Open) { + effects.exit('directiveContainerDataSection') + } + + effects.enter('directiveContainerSectionSequence') + return closingSectionSequence(code) + } + + function closingSectionSequence(code: number) { + if (code === Codes.dash || markdownSpace(code)) { + effects.consume(code) + size++ + return closingSectionSequence + } + + if (size < SectionSequenceSize) return nok(code) + + if (sectionIndentSize !== initialPrefix) return nok(code) + if (!markdownLineEnding(code)) return nok(code) + + effects.exit('directiveContainerSectionSequence') + return createSpace(effects, ok, 'whitespace')(code) + } + } + + function sectionOpen(code: number) { + if (sectionState === MarkDownDataSectionState.NotSeen) { + effects.enter('directiveContainerDataSection') + sectionState = MarkDownDataSectionState.Open + } else { + sectionState = MarkDownDataSectionState.Closed + effects.enter('directiveContainerSection') + } + + return createSpace(effects, ok, 'whitespace')(code) + } +} + function tokenizeLabel(effects: Effects, ok: Okay, nok: NotOkay) { // Always a `[` return createLabel( diff --git a/src/core/parser/markdown/directive/remark-directive/from-markdown.ts b/src/core/parser/markdown/directive/remark-directive/from-markdown.ts index 1a31754d2..900ea2c42 100644 --- a/src/core/parser/markdown/directive/remark-directive/from-markdown.ts +++ b/src/core/parser/markdown/directive/remark-directive/from-markdown.ts @@ -5,6 +5,7 @@ const canContainEols = ['textDirective'] const enter = { directiveContainer: enterContainer, directiveContainerSection: enterContainerSection, + directiveContainerDataSection: enterContainerDataSection, directiveContainerAttributes: enterAttributes, directiveContainerLabel: enterContainerLabel, @@ -21,6 +22,7 @@ const exit = { listOrdered: conditionalExit, listItem: conditionalExit, directiveContainerSection: exitContainerSection, + directiveContainerDataSection: exitContainerDataSection, directiveContainer: exitContainer, directiveContainerAttributeClassValue: exitAttributeClassValue, directiveContainerAttributeIdValue: exitAttributeIdValue, @@ -61,11 +63,14 @@ function enterContainer(token: Token) { function exitContainer(token: Token) { const container = this.stack[this.stack.length - 1] if (container.children.length > 1) { - const dataSection = container.children.shift() - container.rawData = dataSection.raw + const dataSection = container.children.find(child => child.rawData) + container.rawData = dataSection?.rawData } container.children = container.children.flatMap(child => { + if (child.rawData) { + return [] + } if (child.name === 'default' || !child.name) { return child.children } @@ -86,7 +91,15 @@ function enterContainerSection(token: Token) { enterToken.call(this, 'directiveContainerSection', token) } +function enterContainerDataSection(token: Token) { + enterToken.call(this, 'directiveContainerDataSection', token) +} + function exitContainerSection(token: Token) { + this.exit(token) +} + +function exitContainerDataSection(token: Token) { let section = this.stack[this.stack.length - 1] /** * Ensure lists and list-items are closed before closing section @@ -97,8 +110,8 @@ function exitContainerSection(token: Token) { section = this.stack[this.stack.length - 1] } - if (section.type === 'directiveContainerSection') { - section.raw = this.sliceSerialize(token) + if (section.type === 'directiveContainerDataSection') { + section.rawData = this.sliceSerialize(token) this.exit(token) } } diff --git a/src/core/runtime/utils.ts b/src/core/runtime/utils.ts index 9491cdd8d..2bab5d206 100644 --- a/src/core/runtime/utils.ts +++ b/src/core/runtime/utils.ts @@ -52,6 +52,9 @@ export function nodeChildren(vnode) { * @returns text content of given node */ export function nodeTextContent(vnode: any) { + // Return empty string is vnode is falsy + if (!vnode) return '' + if (Array.isArray(vnode)) { return vnode.map(nodeTextContent).join('') }