undocs 0.2.2 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) UnJS
3
+ Copyright (c) Pooya Parsa <pooya@pi0.io>
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -6,8 +6,38 @@ Made with [Nuxt](https://nuxt.com/), [Nuxt Content](https://content.nuxt.com), [
6
6
 
7
7
  👉 Docs: https://undocs.pages.dev/
8
8
 
9
+ ## Contribution
10
+
11
+ <details>
12
+ <summary>Local development</summary>
13
+
14
+ - Clone this repository
15
+ - Install the latest LTS version of [Node.js](https://nodejs.org/en/)
16
+ - Enable [Corepack](https://github.com/nodejs/corepack) using `corepack enable`
17
+ - Install dependencies using `pnpm install`
18
+ - Run tests using `pnpm dev` or `pnpm test`
19
+
20
+ </details>
21
+
22
+ <!-- /automd -->
23
+
9
24
  ## License
10
25
 
11
- Thanks to [@loklaan](https://github.com/loklaan) for donating `undocs` npm package name.
26
+ <!-- automd:contributors license=MIT author="pi0,atinux" -->
27
+
28
+ Published under the [MIT](https://github.com/unjs/undocs/blob/main/LICENSE) license.
29
+ Made by [@pi0](https://github.com/pi0), [@atinux](https://github.com/atinux) and [community](https://github.com/unjs/undocs/graphs/contributors) 💛
30
+ <br><br>
31
+ <a href="https://github.com/unjs/undocs/graphs/contributors">
32
+ <img src="https://contrib.rocks/image?repo=unjs/undocs" />
33
+ </a>
34
+
35
+ <!-- /automd -->
36
+
37
+ <!-- automd:with-automd -->
38
+
39
+ ---
40
+
41
+ _🤖 auto updated with [automd](https://automd.unjs.io) (last updated: Wed Feb 21 2024)_
12
42
 
13
- [MIT](./LICENSE)
43
+ <!-- /automd -->
package/bin/cli.mjs CHANGED
@@ -1,4 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import jiti from 'jiti'
3
-
4
- jiti(import.meta.url, { esmResolve: true })('../layers/unjs/cli/main.ts')
2
+ import '../layers/unjs/cli/main.mjs'
@@ -20,21 +20,19 @@ provide('navigation', navigation)
20
20
  </script>
21
21
 
22
22
  <template>
23
- <div>
24
- <AppHeader />
23
+ <AppHeader />
25
24
 
26
- <UMain>
27
- <NuxtLayout>
28
- <NuxtPage />
29
- </NuxtLayout>
30
- </UMain>
25
+ <UMain class="min-h-[calc(100vh-var(--header-height)-78px)]">
26
+ <NuxtLayout>
27
+ <NuxtPage />
28
+ </NuxtLayout>
29
+ </UMain>
31
30
 
32
- <AppFooter />
31
+ <AppFooter />
33
32
 
34
- <ClientOnly>
35
- <LazyUDocsSearch :files="files" :navigation="navigation" />
36
- </ClientOnly>
33
+ <ClientOnly>
34
+ <LazyUDocsSearch :files="files" :navigation="navigation" />
35
+ </ClientOnly>
37
36
 
38
- <UNotifications />
39
- </div>
37
+ <UNotifications />
40
38
  </template>
@@ -1,14 +1,12 @@
1
1
  <script lang="ts" setup>
2
- import { AppFooterNotes } from '#components'
2
+ import { AppFooterNotes, UDivider } from '#components'
3
3
  </script>
4
4
 
5
5
  <template>
6
- <div class="w-full h-px bg-gray-200 dark:bg-gray-800 flex items-center justify-center">
7
- <div class="bg-white dark:bg-gray-900 px-4">
8
- <OrgLogo class="w-5 h-5" />
9
- </div>
10
- </div>
11
- <UFooter :links="[]">
6
+ <UDivider class="-mb-[10px]">
7
+ <OrgLogo class="w-5 h-5 z-10" />
8
+ </UDivider>
9
+ <UFooter :links="[]" class="bg-background/75 backdrop-blur">
12
10
  <template #left>
13
11
  <AppFooterNotes />
14
12
  </template>
@@ -0,0 +1,45 @@
1
+ <script setup lang="ts">
2
+ const points = useState(() => new Array(16).fill(0).map(() => [Math.random(), Math.random()]))
3
+
4
+ const poly = computed(() => points.value.map(([x, y]) => `${x * 100}% ${y * 100}%`).join(', '))
5
+
6
+ function jumpVal(val: number) {
7
+ return Math.random() > 0.5 ? val + (Math.random() - 0.5) / 2 : Math.random()
8
+ }
9
+
10
+ let timeout
11
+ function jumpPoints() {
12
+ for (let i = 0; i < points.value.length; i++) {
13
+ points.value[i] = [jumpVal(points.value[i][0]), jumpVal(points.value[i][1])]
14
+ }
15
+ timeout = setTimeout(jumpPoints, 2000 + Math.random() * 1000)
16
+ }
17
+
18
+ onMounted(() => {
19
+ jumpPoints()
20
+ onUnmounted(() => clearTimeout(timeout))
21
+ })
22
+ </script>
23
+
24
+ <template>
25
+ <div
26
+ class="bg absolute left-0 right-0 top-0 bottom-0 -z-10 transform-gpu blur-3xl overflow-hidden"
27
+ aria-hidden="true"
28
+ >
29
+ <div
30
+ class="aspect-[1.7] w-full bg-gradient-to-r from-[rgb(var(--color-primary-DEFAULT))] to-white/10 lg:opacity-30 xs:opacity-50"
31
+ :style="{ 'clip-path': `polygon(${poly})` }"
32
+ />
33
+ </div>
34
+ </template>
35
+
36
+ <style scoped>
37
+ .bg > div {
38
+ clip-path: circle(75%);
39
+ transition: clip-path 3s;
40
+ }
41
+
42
+ .light .bg > div {
43
+ opacity: 1 !important;
44
+ }
45
+ </style>
@@ -1,10 +1,10 @@
1
1
  import { fileURLToPath } from 'node:url'
2
2
  import { defineNuxtModule } from 'nuxt/kit'
3
3
  import type { ModuleOptions as ContentOptions } from '@nuxt/content'
4
- import type { DocsConfig } from '../../../schema'
4
+ import type { DocsConfig } from '../../../../../schema/config'
5
5
 
6
6
  export default defineNuxtModule({
7
- setup(_, nuxt) {
7
+ async setup(_, nuxt) {
8
8
  if (nuxt.options._prepare) {
9
9
  return
10
10
  }
@@ -12,6 +12,22 @@ export default defineNuxtModule({
12
12
  const contentConfig = (nuxt.options as any).content as ContentOptions
13
13
  const docsConfig = (nuxt.options as any).docs as DocsConfig
14
14
 
15
+ if (docsConfig.landing === false) {
16
+ nuxt.hooks.hook('pages:extend', (pages) => {
17
+ const index = pages.findIndex((page) => page.path === '/')
18
+ if (index !== -1) {
19
+ pages.splice(index, 1)
20
+ }
21
+ })
22
+ }
23
+
24
+ if (docsConfig.automd) {
25
+ const { loadConfig } = await import('automd')
26
+ docsConfig.automd = loadConfig(docsConfig.dir, {
27
+ ...docsConfig.automd,
28
+ })
29
+ }
30
+
15
31
  contentConfig.sources = {
16
32
  ...contentConfig.sources,
17
33
  content: {
@@ -1,6 +1,9 @@
1
1
  import defu from 'defu'
2
2
 
3
3
  export function genLanding(docsConfig) {
4
+ if (docsConfig.landing === false) {
5
+ return undefined
6
+ }
4
7
  const landing = defu(docsConfig.landing || {}, {
5
8
  // Meta
6
9
  navigation: false,
@@ -35,6 +38,8 @@ export function genLanding(docsConfig) {
35
38
  // Features
36
39
  featuresTitle: '',
37
40
  features: [],
41
+
42
+ _github: docsConfig.github,
38
43
  })
39
44
 
40
45
  landing._heroMdTitle =
@@ -1,5 +1,6 @@
1
1
  import { defineDriver } from 'unstorage'
2
2
  import fsDriver from 'unstorage/drivers/fs'
3
+ import { transform } from 'automd'
3
4
 
4
5
  export default (opts) => {
5
6
  const _fs = fsDriver({
@@ -11,19 +12,40 @@ export default (opts) => {
11
12
  name: 'content',
12
13
  async getItem(key) {
13
14
  const val = await _fs.getItem(key)
14
- if (!val && key === 'index.json') {
15
- return await import('./landing.mjs').then(({ genLanding }) => genLanding(opts.docsConfig))
15
+
16
+ // Landing
17
+ if (opts.docsConfig.landing !== false) {
18
+ if (!val && key === 'index.json') {
19
+ return await import('./landing.mjs').then(({ genLanding }) => genLanding(opts.docsConfig))
20
+ }
21
+ if (!val && key === 'index.json$') {
22
+ return { mtime: new Date() }
23
+ }
16
24
  }
17
- if (!val && key === 'index.json$') {
18
- return { mtime: new Date() }
25
+
26
+ // Automd transform
27
+ if (opts.docsConfig.automd) {
28
+ if (key.endsWith('.md') && typeof val === 'string') {
29
+ const res = await transform(val, opts.docsConfig.automd)
30
+ if (res.hasChanged) {
31
+ _fs.setItem(key, res.contents).catch(console.error)
32
+ }
33
+ return res.contents
34
+ } else if (key.endsWith('.md$')) {
35
+ return { mtime: new Date() }
36
+ }
19
37
  }
38
+
20
39
  return val
21
40
  },
22
41
  async getKeys(prefix) {
23
42
  const keys = await _fs.getKeys(prefix)
24
- if (!keys.some((key) => /^index\.\w+$/.test(key))) {
43
+
44
+ // Landing
45
+ if (opts.docsConfig.landing !== false && !keys.some((key) => /^index\.\w+$/.test(key))) {
25
46
  keys.push('index.json')
26
47
  }
48
+
27
49
  return keys
28
50
  },
29
51
  })
@@ -15,7 +15,6 @@ export default defineNuxtConfig({
15
15
  ssr,
16
16
  modules: [
17
17
  '@nuxt/content',
18
- '@nuxthq/studio',
19
18
  '@nuxtjs/fontaine',
20
19
  !isPrepare && '@nuxtjs/google-fonts',
21
20
  '@nuxtjs/seo',
@@ -112,4 +111,8 @@ export default defineNuxtConfig({
112
111
  strict: false,
113
112
  includeWorkspace: true,
114
113
  },
114
+ colorMode: {
115
+ preference: 'dark',
116
+ fallback: 'dark',
117
+ },
115
118
  })
@@ -63,32 +63,45 @@ const hero = computed(() => {
63
63
  return
64
64
  }
65
65
  const code = formatHeroCode(page.value!.heroCode)
66
+ const withFeatures = !code && page.value.featuresLayout === 'hero' && page.value.features?.length > 0
66
67
  return {
67
68
  title: page.value!._heroMdTitle,
68
69
  description: page.value!.heroDescription,
69
70
  links: nornalizeHeroLinks(page.value!.heroLinks),
70
- orientation: code ? 'horizontal' : 'vertical',
71
+ withFeatures,
72
+ orientation: code || withFeatures ? 'horizontal' : 'vertical',
71
73
  code,
72
74
  } as const
73
75
  })
74
76
  </script>
75
77
 
76
78
  <template>
77
- <div>
78
- <ULandingHero v-if="hero" v-bind="hero">
79
- <template #title>
80
- <MDC :value="hero.title" />
81
- </template>
79
+ <ULandingHero v-if="hero" v-bind="hero" :orientation="hero.orientation">
80
+ <template #top>
81
+ <LandingBackground />
82
+ </template>
83
+ <template #title>
84
+ <MDC :value="hero.title" />
85
+ </template>
82
86
 
83
- <MDC v-if="hero.code" :value="hero.code" tag="pre" class="prose prose-primary dark:prose-invert mx-auto" />
84
- </ULandingHero>
87
+ <MDC v-if="hero.code" :value="hero.code" tag="pre" class="prose prose-primary dark:prose-invert mx-auto" />
88
+ <div v-else-if="hero.withFeatures" class="flex flex-col gap-6">
89
+ <ULandingCard v-for="(item, index) of page.features" :key="index" v-bind="item" />
90
+ </div>
91
+ </ULandingHero>
92
+ <template v-if="page.features?.length > 0 && !hero.withFeatures">
93
+ <ULandingSection :title="page.featuresTitle">
94
+ <UPageGrid>
95
+ <ULandingCard v-for="(item, index) of page.features" :key="index" v-bind="item" />
96
+ </UPageGrid>
97
+ </ULandingSection>
98
+ </template>
85
99
 
86
- <template v-if="page.features">
87
- <ULandingSection :title="page.featuresTitle">
88
- <UPageGrid>
89
- <ULandingCard v-for="(item, index) of page.features" :key="index" v-bind="item" />
90
- </UPageGrid>
91
- </ULandingSection>
92
- </template>
93
- </div>
100
+ <ULandingSection v-if="page.contributors && page._github" title="Made by community">
101
+ <UContainer>
102
+ <a :href="`https://github.com/${page._github}/graphs/contributors`" target="_blank">
103
+ <img :src="`https://contrib.rocks/image?repo=${page._github}`" />
104
+ </a>
105
+ </UContainer>
106
+ </ULandingSection>
94
107
  </template>
@@ -6,15 +6,18 @@ export default defineNitroPlugin((nitroApp) => {
6
6
  }
7
7
 
8
8
  // Remove first h1 from markdown files as it is added to front-matter as title
9
- if (file.body?.children?.[0]?.tag === 'h1' && file.title === file.body.children[0].children?.[0]?.value) {
10
- file.body.children.shift()
9
+ if (file.body?.children?.[0]?.tag === 'h1') {
10
+ const text = getTextContents(file.body.children[0].children)
11
+ if (file.title === text) {
12
+ file.body.children.shift()
13
+ }
11
14
  }
12
15
 
13
16
  // Only use the first blockquote as the description
14
17
  const firstChild = file.body.children?.[0]
15
- const firstChildContent = firstChild?.children?.[0]?.children?.[0]?.value
16
- if (firstChild.tag === 'blockquote' && firstChildContent) {
17
- file.description = firstChildContent
18
+ const firstChildText = getTextContents(firstChild?.children)
19
+ if (firstChild?.tag === 'blockquote' && firstChildText && !firstChildText.startsWith('!')) {
20
+ file.description = firstChildText
18
21
  file.body.children.shift()
19
22
  } else {
20
23
  file.description = '' // Avoid duplication
@@ -36,3 +39,14 @@ export default defineNitroPlugin((nitroApp) => {
36
39
  }
37
40
  })
38
41
  })
42
+
43
+ function getTextContents(children) {
44
+ return (children || [])
45
+ .map((child) => {
46
+ if (child.type === 'element') {
47
+ return getTextContents(child.children)
48
+ }
49
+ return child.value
50
+ })
51
+ .join('')
52
+ }
@@ -1,14 +1,14 @@
1
- #!/usr/bin/env node
2
1
  import { defineCommand, runMain } from 'citty'
3
- import { setupDocs, type SetupDocsOptions } from './setup'
2
+ import { setupDocs } from './setup.mjs'
3
+ // import type { SetupDocsOptions } from './setup.mjs'
4
4
 
5
- export interface DocsCLIOptions {
6
- name?: string
7
- description?: string
8
- setup?: SetupDocsOptions
9
- }
5
+ // export interface DocsCLIOptions {
6
+ // name?: string
7
+ // description?: string
8
+ // setup?: SetupDocsOptions
9
+ // }
10
10
 
11
- export function createCLI(opts: DocsCLIOptions = {}) {
11
+ export function createCLI(opts) {
12
12
  const sharedArgs = {
13
13
  dir: {
14
14
  type: 'positional',
@@ -16,7 +16,7 @@ export function createCLI(opts: DocsCLIOptions = {}) {
16
16
  required: true,
17
17
  default: '.',
18
18
  },
19
- } as const
19
+ }
20
20
 
21
21
  const dev = defineCommand({
22
22
  meta: {
@@ -1,22 +1,22 @@
1
1
  import { fileURLToPath } from 'node:url'
2
2
  import { resolve } from 'node:path'
3
- import type { NuxtConfig } from 'nuxt/schema'
3
+ // import type { NuxtConfig } from 'nuxt/schema'
4
4
  import { getColors } from 'theme-colors'
5
5
  import { loadConfig } from 'c12'
6
- import type { DocsConfig } from '../../../schema/config'
6
+ // import type { DocsConfig } from '../../../schema/config'
7
7
 
8
8
  const appDir = fileURLToPath(new URL('../app', import.meta.url))
9
9
  const pkgDir = fileURLToPath(new URL('../../..', import.meta.url))
10
10
 
11
- export interface SetupDocsOptions {
12
- defaults?: DocsConfig
13
- dev?: boolean
14
- extends?: string[]
15
- }
11
+ // export interface SetupDocsOptions {
12
+ // defaults?: DocsConfig
13
+ // dev?: boolean
14
+ // extends?: string[]
15
+ // }
16
16
 
17
- export async function setupDocs(docsDir: string, opts: SetupDocsOptions = {}) {
17
+ export async function setupDocs(docsDir, opts = {}) {
18
18
  // Try to load docs config
19
- const docsconfig = (await loadDocsConfig(docsDir, opts.defaults)) || ({} as DocsConfig)
19
+ const docsconfig = (await loadDocsConfig(docsDir, opts.defaults)) || {}
20
20
 
21
21
  // Normalize dir
22
22
  docsconfig.dir = docsDir = resolve(docsconfig.dir || docsDir)
@@ -27,7 +27,7 @@ export async function setupDocs(docsDir: string, opts: SetupDocsOptions = {}) {
27
27
  }
28
28
 
29
29
  // Prepare loadNuxt overrides
30
- const nuxtConfig: NuxtConfig = {
30
+ const nuxtConfig = {
31
31
  rootDir: resolve(docsDir, '.docs'),
32
32
  srcDir: resolve(docsDir, '.docs'),
33
33
 
@@ -85,8 +85,8 @@ export async function setupDocs(docsDir: string, opts: SetupDocsOptions = {}) {
85
85
  }
86
86
  }
87
87
 
88
- async function loadDocsConfig(dir: string, defaults: DocsConfig = {}) {
89
- const { config } = await loadConfig<DocsConfig>({
88
+ async function loadDocsConfig(dir, defaults = {}) {
89
+ const { config } = await loadConfig({
90
90
  name: 'docs',
91
91
  cwd: dir,
92
92
  defaults: {
@@ -1,5 +1,5 @@
1
1
  import { fileURLToPath } from 'node:url'
2
- import { createCLI } from '../../core/cli/cli'
2
+ import { createCLI } from '../../core/cli/cli.mjs'
3
3
 
4
4
  const appDir = fileURLToPath(new URL('../app', import.meta.url))
5
5
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "undocs",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "repository": "unjs/undocs",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -17,32 +17,35 @@
17
17
  "scripts": {
18
18
  "build": "true",
19
19
  "dev": "bun run docs:dev",
20
- "docs:dev": "NUXT_DOCS_DEV=1 bun run undocs dev docs",
21
20
  "docs:build": "bun run undocs build docs",
22
- "template:dev": "bun run undocs dev template",
21
+ "docs:dev": "NUXT_DOCS_DEV=1 bun run undocs dev docs",
23
22
  "lint": "eslint --cache --ext .ts,.js,.mjs,.cjs . && prettier -c layers",
24
23
  "lint:fix": "eslint --cache --ext .ts,.js,.mjs,.cjs . --fix && prettier -c -w layers",
25
24
  "prepack": "bun run build",
25
+ "profile:0x": "bunx 0x -o bin/cli.mjs dev docs",
26
+ "profile:0x-kernel": "bun run profile:0x --kernel-tracing",
27
+ "profile:cpu": "rm -rf .profile && node --cpu-prof --diagnostic-dir ../../../.profile bin/cli.mjs dev docs",
26
28
  "release": "bun run lint && changelogen --release && npm publish && git push --follow-tags",
29
+ "template:dev": "bun run undocs dev template",
27
30
  "undocs": "./bin/cli.mjs"
28
31
  },
29
32
  "dependencies": {
30
33
  "@nuxt/content": "^2.12.0",
31
34
  "@nuxt/ui": "^2.13.0",
32
35
  "@nuxt/ui-pro": "^0.7.5",
33
- "@nuxthq/studio": "^1.0.10",
34
36
  "@nuxtjs/fontaine": "^0.4.1",
35
37
  "@nuxtjs/google-fonts": "^3.1.3",
36
38
  "@nuxtjs/plausible": "^0.2.4",
37
39
  "@nuxtjs/seo": "^2.0.0-rc.8",
38
40
  "@nuxtjs/tailwindcss": "^6.11.3",
41
+ "automd": "^0.3.2",
39
42
  "c12": "^1.7.0",
40
43
  "citty": "^0.1.5",
41
44
  "consola": "^3.2.3",
42
45
  "defu": "^6.1.4",
43
46
  "is-buffer": "^2.0.5",
44
- "nuxi": "^3.10.0",
45
- "nuxt": "^3.10.1",
47
+ "nuxi": "^3.10.1",
48
+ "nuxt": "^3.10.2",
46
49
  "nuxt-build-cache": "^0.1.1",
47
50
  "pkg-types": "^1.0.3",
48
51
  "scule": "^1.3.0",
@@ -7,16 +7,24 @@ export interface DocsConfig {
7
7
  github?: string
8
8
  themeColor?: string
9
9
  redirects?: Record<string, string>
10
- landing?: {
11
- title?: string
12
- description?: string
13
- _heroMdTitle?: string
14
- heroTitle?: string
15
- heroSubtitle?: string
16
- heroDescription?: string
17
- heroLinks?: Record<string, string | { label?: string; icon?: string; to?: string; size?: string; order?: number }>
18
- heroCode?: string | { content: string; title?: string; lang?: string }
19
- featuresTitle?: string
20
- features?: { title: string; description?: string; icon?: string }[]
21
- }
10
+ automd?: any
11
+ contributors?: boolean
12
+ landing?:
13
+ | false
14
+ | {
15
+ title?: string
16
+ description?: string
17
+ _heroMdTitle?: string
18
+ heroTitle?: string
19
+ heroSubtitle?: string
20
+ heroDescription?: string
21
+ heroLinks?: Record<
22
+ string,
23
+ string | { label?: string; icon?: string; to?: string; size?: string; order?: number }
24
+ >
25
+ heroCode?: string | { content: string; title?: string; lang?: string }
26
+ featuresTitle?: string
27
+ featuresLayout?: 'default' | 'hero'
28
+ features?: { title: string; description?: string; icon?: string }[]
29
+ }
22
30
  }
@@ -34,6 +34,10 @@
34
34
  "type": "string",
35
35
  "description": "The theme color of the documentation site.\nIt will be used as the `theme-color` meta tag and a full palette of colors will be generated from it."
36
36
  },
37
+ "automd": {
38
+ "type": "boolean",
39
+ "description": "Enable integration with https://automd.unjs.io"
40
+ },
37
41
  "redirects": {
38
42
  "description": "Redirects for the documentation site.",
39
43
  "type": "object",
@@ -42,84 +46,101 @@
42
46
  }
43
47
  },
44
48
  "landing": {
45
- "type": "object",
46
- "description": "Landing page configuration",
47
- "additionalProperties": false,
48
- "properties": {
49
- "description": {
50
- "type": "string",
51
- "description": "Page description"
49
+ "oneOf": [
50
+ {
51
+ "type": "boolean",
52
+ "const": false
52
53
  },
53
- "features": {
54
- "type": "array",
55
- "description": "Features section description",
56
- "items": {
57
- "type": "object",
58
- "properties": {
59
- "description": {
60
- "type": "string"
61
- },
62
- "icon": {
63
- "type": "string"
64
- },
65
- "title": {
66
- "type": "string"
54
+ {
55
+ "type": "object",
56
+ "description": "Landing page configuration",
57
+ "additionalProperties": false,
58
+ "properties": {
59
+ "description": {
60
+ "type": "string",
61
+ "description": "Page description"
62
+ },
63
+ "contributors": {
64
+ "type": "boolean",
65
+ "description": "Show contributors section"
66
+ },
67
+ "features": {
68
+ "type": "array",
69
+ "description": "Features section description",
70
+ "items": {
71
+ "type": "object",
72
+ "properties": {
73
+ "description": {
74
+ "type": "string"
75
+ },
76
+ "icon": {
77
+ "type": "string"
78
+ },
79
+ "title": {
80
+ "type": "string"
81
+ }
82
+ }
67
83
  }
68
- }
69
- }
70
- },
71
- "featuresTitle": {
72
- "type": "string",
73
- "description": "Features section title"
74
- },
75
- "heroCode": {
76
- "description": "Hero Codes",
77
- "anyOf": [
78
- {
79
- "type": "string"
80
84
  },
81
- {
82
- "type": "object",
83
- "additionalProperties": false,
84
- "required": ["content"],
85
- "properties": {
86
- "content": {
87
- "type": "string"
88
- },
89
- "lang": {
85
+ "featuresTitle": {
86
+ "type": "string",
87
+ "description": "Features section title"
88
+ },
89
+ "featuresLayout": {
90
+ "type": "string",
91
+ "description": "Features section layout to be in default place or in the hero (only if there is no code)",
92
+ "enum": ["default", "hero"]
93
+ },
94
+ "heroCode": {
95
+ "description": "Hero Codes",
96
+ "anyOf": [
97
+ {
90
98
  "type": "string"
91
99
  },
92
- "title": {
93
- "type": "string"
100
+ {
101
+ "type": "object",
102
+ "additionalProperties": false,
103
+ "required": ["content"],
104
+ "properties": {
105
+ "content": {
106
+ "type": "string"
107
+ },
108
+ "lang": {
109
+ "type": "string"
110
+ },
111
+ "title": {
112
+ "type": "string"
113
+ }
114
+ }
94
115
  }
116
+ ]
117
+ },
118
+ "heroDescription": {
119
+ "type": "string",
120
+ "description": "Additional text in hero (default is same as description)"
121
+ },
122
+ "heroLinks": {
123
+ "description": "Hero Links",
124
+ "type": "object",
125
+ "additionalProperties": {
126
+ "type": "object"
95
127
  }
128
+ },
129
+ "heroSubtitle": {
130
+ "type": "string",
131
+ "description": "second hero title (default is same as shortDescription)"
132
+ },
133
+ "heroTitle": {
134
+ "type": "string",
135
+ "description": "main title (default is same as page title)"
136
+ },
137
+ "title": {
138
+ "type": "string",
139
+ "description": "Page title"
96
140
  }
97
- ]
98
- },
99
- "heroDescription": {
100
- "type": "string",
101
- "description": "Additional text in hero (default is same as description)"
102
- },
103
- "heroLinks": {
104
- "description": "Hero Links",
105
- "type": "object",
106
- "additionalProperties": {
107
- "type": "object"
108
141
  }
109
- },
110
- "heroSubtitle": {
111
- "type": "string",
112
- "description": "second hero title (default is same as shortDescription)"
113
- },
114
- "heroTitle": {
115
- "type": "string",
116
- "description": "main title (default is same as page title)"
117
- },
118
- "title": {
119
- "type": "string",
120
- "description": "Page title"
121
142
  }
122
- }
143
+ ]
123
144
  }
124
145
  }
125
146
  }