@docsector/docsector-reader 2.0.7 → 2.2.0

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.
Files changed (32) hide show
  1. package/README.md +19 -7
  2. package/bin/docsector.js +28 -7
  3. package/docsector.config.js +13 -1
  4. package/package.json +1 -1
  5. package/src/components/DMenu.vue +241 -12
  6. package/src/components/DMenuItem.vue +25 -2
  7. package/src/components/DPageBar.vue +35 -5
  8. package/src/components/DPageMeta.vue +40 -26
  9. package/src/i18n/helpers.js +84 -18
  10. package/src/i18n/index.js +5 -3
  11. package/src/i18n/languages/en-US.hjson +14 -0
  12. package/src/i18n/languages/pt-BR.hjson +14 -0
  13. package/src/i18n/path.js +15 -2
  14. package/src/index.js +2 -2
  15. package/src/layouts/DefaultLayout.vue +16 -2
  16. package/src/pages/.old/v0.x/guide/getting-started.overview.en-US.md +7 -0
  17. package/src/pages/.old/v0.x/guide/getting-started.overview.pt-BR.md +7 -0
  18. package/src/pages/.old/v0.x/guide.book.js +12 -0
  19. package/src/pages/.old/v0.x/guide.index.js +28 -0
  20. package/src/pages/guide/configuration.overview.en-US.md +13 -2
  21. package/src/pages/guide/configuration.overview.pt-BR.md +13 -2
  22. package/src/pages/guide/pages-and-routing.overview.en-US.md +6 -2
  23. package/src/pages/guide/pages-and-routing.overview.pt-BR.md +6 -2
  24. package/src/pages/guide.index.js +3 -1
  25. package/src/pages/manual/components/d-menu.overview.en-US.md +6 -2
  26. package/src/pages/manual/components/d-menu.overview.pt-BR.md +6 -2
  27. package/src/pages/manual/components/d-page-meta.overview.en-US.md +1 -0
  28. package/src/pages/manual/components/d-page-meta.overview.pt-BR.md +1 -0
  29. package/src/pages/manual.index.js +2 -1
  30. package/src/quasar.factory.js +648 -91
  31. package/src/router/routes.js +129 -95
  32. package/src/store/App.js +15 -5
@@ -20,7 +20,17 @@ function normalizeEditBaseUrl (url = '') {
20
20
 
21
21
  const base = normalizeEditBaseUrl(docsectorConfig.github?.editBaseUrl || '')
22
22
 
23
+ function getCurrentSubpageName () {
24
+ const relative = store.state.page.relative || '/overview'
25
+ return String(relative).replace(/^\/+|\/+$/g, '') || 'overview'
26
+ }
27
+
23
28
  function routePathToSourcePath (path = '') {
29
+ const sourcePathBase = route.matched?.[0]?.meta?.sourcePathBase
30
+ if (typeof sourcePathBase === 'string' && sourcePathBase.length > 0) {
31
+ return `/${sourcePathBase}.${getCurrentSubpageName()}`
32
+ }
33
+
24
34
  const cleanPath = String(path)
25
35
  .replace(/\/index\.html$/, '')
26
36
  .replace(/\/+$/, '')
@@ -44,7 +54,7 @@ const URL = computed(() => {
44
54
  return `${base}${path}.${locale.value}.md`
45
55
  })
46
56
  const color = computed(() => {
47
- if (status.value === 'done') {
57
+ if (status.value === 'done' || status.value === 'new') {
48
58
  return 'white'
49
59
  } else if (status.value === 'draft') {
50
60
  return 'warning'
@@ -53,7 +63,7 @@ const color = computed(() => {
53
63
  }
54
64
  })
55
65
  const icon = computed(() => {
56
- if (status.value === 'done') {
66
+ if (status.value === 'done' || status.value === 'new') {
57
67
  return 'edit'
58
68
  } else if (status.value === 'draft') {
59
69
  return 'border_color'
@@ -131,34 +141,38 @@ const languages = computed(() => {
131
141
  return `${i18nLocalesAvailable}/${i18nLocales.length}`
132
142
  })
133
143
 
134
- const prev = computed(() => {
135
- const base = store.state.page.base
136
- const routes = router.options.routes.slice(0, -2)
137
-
138
- for (let i = 0; i < routes.length; i++) {
139
- if ('/' + base === routes[i].path) {
140
- if (i > 0) {
141
- return routes[i - 1].path
142
- }
143
- }
144
+ const normalizeRoutePath = (path) => {
145
+ const normalized = String(path || '').trim()
146
+ if (normalized === '' || normalized === '/') {
147
+ return '/'
144
148
  }
145
149
 
146
- return ''
150
+ const sanitized = normalized.replace(/\/+$/, '')
151
+ return sanitized === '' ? '/' : sanitized
152
+ }
153
+
154
+ const getVersionSiblingPath = (offset) => {
155
+ const versionId = route.matched?.[0]?.meta?.version ?? null
156
+ const currentPath = normalizeRoutePath(route.matched?.[0]?.path || `/${store.state.page.base}`)
157
+ const routes = router.options.routes
158
+ .slice(0, -2)
159
+ .filter(item => !versionId || item?.meta?.version === versionId)
160
+
161
+ const index = routes.findIndex(item => normalizeRoutePath(item.path) === currentPath)
162
+ if (index < 0) return ''
163
+
164
+ const sibling = routes[index + offset]
165
+ if (!sibling) return ''
166
+
167
+ return sibling.path
168
+ }
169
+
170
+ const prev = computed(() => {
171
+ return getVersionSiblingPath(-1)
147
172
  })
148
173
 
149
174
  const next = computed(() => {
150
- const base = store.state.page.base
151
- const routes = router.options.routes.slice(0, -2)
152
-
153
- for (let i = 0; i < routes.length; i++) {
154
- if ('/' + base === routes[i].path) {
155
- if (typeof routes[i + 1] !== 'undefined') {
156
- return routes[i + 1].path
157
- }
158
- }
159
- }
160
-
161
- return ''
175
+ return getVersionSiblingPath(1)
162
176
  })
163
177
 
164
178
  const hideRemoteHomeFooterMeta = computed(() => {
@@ -180,7 +194,7 @@ const getRouteTitle = (path) => {
180
194
  <div id="d-page-edit" class="col">
181
195
  <q-btn dense no-caps text-color="black" :color="color" @click="openURL(URL)" aria-label="Edit page on Github">
182
196
  <q-icon class="q-mr-xs" name="fab fa-github" size="20px" />
183
- <span class="hm" v-if="status === 'done'">{{ $t('page.edit.github.edit') }}</span>
197
+ <span class="hm" v-if="status === 'done' || status === 'new'">{{ $t('page.edit.github.edit') }}</span>
184
198
  <span class="hm" v-else-if="status === 'draft'">{{ $t('page.edit.github.complete') }}</span>
185
199
  <span class="hm" v-else-if="status === 'empty'">{{ $t('page.edit.github.start') }}</span>
186
200
  </q-btn>
@@ -25,6 +25,7 @@ const engineDefaults = {
25
25
  'en-US': {
26
26
  page: {
27
27
  lastUpdated: 'Last updated',
28
+ newVersion: 'New in',
28
29
  copyPage: 'Copy page',
29
30
  copyPageCaption: 'Copy page as Markdown for LLMs',
30
31
  copied: 'Copied!',
@@ -44,11 +45,36 @@ const engineDefaults = {
44
45
  connectClaudeCodeCaption: 'Use this MCP in Claude Code',
45
46
  connectCodex: 'Connect to Codex',
46
47
  connectCodexCaption: 'Use this MCP in Codex'
48
+ },
49
+ menu: {
50
+ status: {
51
+ empty: {
52
+ _: 'empty',
53
+ tooltip: 'This page is empty!'
54
+ },
55
+ draft: {
56
+ _: 'draft',
57
+ tooltip: 'This page is under construction.'
58
+ },
59
+ new: {
60
+ _: 'new',
61
+ tooltip: 'This page is new.',
62
+ tooltipVersion: 'New in {version}'
63
+ }
64
+ },
65
+ version: {
66
+ status: {
67
+ released: 'released',
68
+ draft: 'draft',
69
+ deprecated: 'deprecated'
70
+ }
71
+ }
47
72
  }
48
73
  },
49
74
  'pt-BR': {
50
75
  page: {
51
76
  lastUpdated: 'Última atualização',
77
+ newVersion: 'Novo em',
52
78
  copyPage: 'Copiar página',
53
79
  copyPageCaption: 'Copiar página como Markdown para LLMs',
54
80
  copied: 'Copiado!',
@@ -68,6 +94,30 @@ const engineDefaults = {
68
94
  connectClaudeCodeCaption: 'Use este MCP no Claude Code',
69
95
  connectCodex: 'Conectar ao Codex',
70
96
  connectCodexCaption: 'Use este MCP no Codex'
97
+ },
98
+ menu: {
99
+ status: {
100
+ empty: {
101
+ _: 'vazia',
102
+ tooltip: 'Esta página está vazia!'
103
+ },
104
+ draft: {
105
+ _: 'rascunho',
106
+ tooltip: 'Esta página está em construção.'
107
+ },
108
+ new: {
109
+ _: 'novo',
110
+ tooltip: 'Esta página é nova.',
111
+ tooltipVersion: 'Novo na {version}'
112
+ }
113
+ },
114
+ version: {
115
+ status: {
116
+ released: 'publicada',
117
+ draft: 'rascunho',
118
+ deprecated: 'obsoleta'
119
+ }
120
+ }
71
121
  }
72
122
  }
73
123
  }
@@ -116,12 +166,13 @@ export function filter (source) {
116
166
  * @param {Object} options.mdModules - Result of recursively globbing markdown files under ../pages with eager raw imports
117
167
  * @param {Object} [options.pages] - Legacy merged page registry from virtual:docsector-books (allPages)
118
168
  * @param {Object} [options.books] - Book registry from virtual:docsector-books (preferred, avoids path collisions)
169
+ * @param {Array} [options.pageEntries] - Version-aware page entries from virtual:docsector-books
119
170
  * @param {Object} options.boot - Boot meta from pages/boot.js
120
171
  * @param {string[]} [options.langs] - Language codes to process (auto-detected from langModules if omitted)
121
172
  * @param {Object<string,string>} [options.homePageOverride] - Optional per-language Home markdown override
122
173
  * @returns {Object} Complete i18n messages object keyed by locale
123
174
  */
124
- export function buildMessages ({ langModules, mdModules, pages, books, boot, langs, homePageOverride = {} }) {
175
+ export function buildMessages ({ langModules, mdModules, pages, books, pageEntries, boot, langs, homePageOverride = {} }) {
125
176
  // Auto-detect languages from HJSON files if not provided
126
177
  if (!langs) {
127
178
  langs = Object.keys(langModules).map(key => {
@@ -133,8 +184,9 @@ export function buildMessages ({ langModules, mdModules, pages, books, boot, lan
133
184
 
134
185
  const i18n = {}
135
186
 
136
- function load (topPage, path, subpage, lang) {
137
- const key = `../pages/${topPage}/${path}.${subpage}.${lang}.md`
187
+ function load (topPage, path, subpage, lang, sourceRoot = '') {
188
+ const normalizedSourceRoot = String(sourceRoot || '').replace(/^\/+|\/+$/g, '')
189
+ const key = `../pages/${normalizedSourceRoot ? normalizedSourceRoot + '/' : ''}${topPage}/${path}.${subpage}.${lang}.md`
138
190
  const content = mdModules[key]
139
191
 
140
192
  if (!content) {
@@ -200,20 +252,30 @@ export function buildMessages ({ langModules, mdModules, pages, books, boot, lan
200
252
  return match[1].trim()
201
253
  }
202
254
 
203
- const pageEntries = []
255
+ const resolvedPageEntries = []
204
256
 
205
- if (books && typeof books === 'object' && Object.keys(books).length > 0) {
257
+ if (Array.isArray(pageEntries) && pageEntries.length > 0) {
258
+ for (const entry of pageEntries) {
259
+ resolvedPageEntries.push({
260
+ key: entry.pagePath,
261
+ page: entry.page,
262
+ fallbackBook: entry.book,
263
+ sourceRoot: entry.sourceRoot || '',
264
+ i18nSegments: entry.i18nSegments
265
+ })
266
+ }
267
+ } else if (books && typeof books === 'object' && Object.keys(books).length > 0) {
206
268
  for (const [bookId, book] of Object.entries(books)) {
207
269
  const routes = book?.routes || {}
208
270
  const fallbackBook = book?.config?.id || bookId || 'manual'
209
271
 
210
272
  for (const [key, page] of Object.entries(routes)) {
211
- pageEntries.push({ key, page, fallbackBook })
273
+ resolvedPageEntries.push({ key, page, fallbackBook })
212
274
  }
213
275
  }
214
276
  } else {
215
277
  for (const [key, page] of Object.entries(pages || {})) {
216
- pageEntries.push({ key, page, fallbackBook: null })
278
+ resolvedPageEntries.push({ key, page, fallbackBook: null })
217
279
  }
218
280
  }
219
281
 
@@ -249,8 +311,8 @@ export function buildMessages ({ langModules, mdModules, pages, books, boot, lan
249
311
  i18n[lang]._.home.overview.source = loadHomepage(lang)
250
312
 
251
313
  // @ Iterate pages
252
- for (const entry of pageEntries) {
253
- const { key, page, fallbackBook } = entry
314
+ for (const entry of resolvedPageEntries) {
315
+ const { key, page, fallbackBook, sourceRoot = '', i18nSegments: entryI18nSegments } = entry
254
316
  const path = key.startsWith('/') ? key.slice(1) : key
255
317
 
256
318
  const config = page.config
@@ -258,13 +320,13 @@ export function buildMessages ({ langModules, mdModules, pages, books, boot, lan
258
320
  const meta = page.meta || boot.meta
259
321
 
260
322
  const topPage = config?.book ?? config?.type ?? fallbackBook ?? 'manual'
261
- if (i18n[lang]._[topPage] === undefined) {
262
- i18n[lang]._[topPage] = {}
263
- }
323
+ const i18nSegments = Array.isArray(entryI18nSegments) && entryI18nSegments.length > 0
324
+ ? entryI18nSegments
325
+ : [topPage, ...path.split('/').filter(Boolean)]
264
326
 
265
327
  // ---
266
328
 
267
- const _ = path.split('/').reduce((accumulator, current) => {
329
+ const _ = i18nSegments.reduce((accumulator, current, index) => {
268
330
  let node = accumulator[current]
269
331
 
270
332
  // Set object if not exists
@@ -275,7 +337,7 @@ export function buildMessages ({ langModules, mdModules, pages, books, boot, lan
275
337
 
276
338
  // @ Set metadata
277
339
  // title
278
- if (node._ === undefined) {
340
+ if (index === i18nSegments.length - 1 && node._ === undefined) {
279
341
  node._ = data?.[lang]?.title || data?.['*']?.title || data?.['en-US']?.title || ''
280
342
  }
281
343
 
@@ -283,6 +345,10 @@ export function buildMessages ({ langModules, mdModules, pages, books, boot, lan
283
345
  return node
284
346
  }
285
347
 
348
+ if (index < i18nSegments.length - 1) {
349
+ return node
350
+ }
351
+
286
352
  // Set subpages sources if not exists
287
353
  if (node.overview === undefined) {
288
354
  node.overview = {
@@ -307,7 +373,7 @@ export function buildMessages ({ langModules, mdModules, pages, books, boot, lan
307
373
  }
308
374
 
309
375
  return node
310
- }, i18n[lang]._[topPage])
376
+ }, i18n[lang]._)
311
377
 
312
378
  // ---
313
379
 
@@ -322,14 +388,14 @@ export function buildMessages ({ langModules, mdModules, pages, books, boot, lan
322
388
 
323
389
  // @ Subpages
324
390
  // Overview
325
- _.overview.source = load(topPage, path, 'overview', lang)
391
+ _.overview.source = load(topPage, path, 'overview', lang, sourceRoot)
326
392
  // showcase
327
393
  if (config.subpages?.showcase === true) {
328
- _.showcase.source = load(topPage, path, 'showcase', lang)
394
+ _.showcase.source = load(topPage, path, 'showcase', lang, sourceRoot)
329
395
  }
330
396
  // Vs
331
397
  if (config.subpages?.vs === true) {
332
- _.vs.source = load(topPage, path, 'vs', lang)
398
+ _.vs.source = load(topPage, path, 'vs', lang, sourceRoot)
333
399
  }
334
400
  }
335
401
  }
package/src/i18n/index.js CHANGED
@@ -5,10 +5,12 @@ import homePageOverride from 'virtual:docsector-homepage-override'
5
5
  // @ Import language HJSON files (Vite-compatible eager import)
6
6
  const langModules = import.meta.glob('./languages/*.hjson', { eager: true })
7
7
  // @ Import markdown files (Vite-compatible eager import as raw strings)
8
- const mdModules = import.meta.glob('../pages/**/*.md', { eager: true, query: '?raw', import: 'default' })
8
+ const currentMdModules = import.meta.glob('../pages/**/*.md', { eager: true, query: '?raw', import: 'default' })
9
+ const oldMdModules = import.meta.glob('../pages/.old/**/*.md', { eager: true, query: '?raw', import: 'default' })
10
+ const mdModules = { ...currentMdModules, ...oldMdModules }
9
11
 
10
12
  // @ Import pages
11
13
  import boot from 'pages/boot'
12
- import { books } from 'virtual:docsector-books'
14
+ import { books, pageEntries } from 'virtual:docsector-books'
13
15
 
14
- export default buildMessages({ langModules, mdModules, books, boot, homePageOverride })
16
+ export default buildMessages({ langModules, mdModules, books, pageEntries, boot, homePageOverride })
@@ -32,6 +32,7 @@
32
32
  next: 'Next page'
33
33
  },
34
34
  lastUpdated: 'Last updated',
35
+ newVersion: 'New in',
35
36
  copyPage: 'Copy page',
36
37
  copyPageCaption: 'Copy page as Markdown for LLMs',
37
38
  copied: 'Copied!',
@@ -60,6 +61,19 @@
60
61
  draft: {
61
62
  _: 'draft',
62
63
  tooltip: 'This page is under constrution.'
64
+ },
65
+ new: {
66
+ _: 'new',
67
+ tooltip: 'This page is new.',
68
+ tooltipVersion: 'New in {version}'
69
+ }
70
+ },
71
+
72
+ version: {
73
+ status: {
74
+ released: 'released',
75
+ draft: 'draft',
76
+ deprecated: 'deprecated'
63
77
  }
64
78
  },
65
79
 
@@ -31,6 +31,7 @@
31
31
  next: 'Próxima página'
32
32
  },
33
33
  lastUpdated: 'Última atualização',
34
+ newVersion: 'Novo em',
34
35
  copyPage: 'Copiar página',
35
36
  copyPageCaption: 'Copiar página como Markdown para LLMs',
36
37
  copied: 'Copiado!',
@@ -59,6 +60,19 @@
59
60
  draft: {
60
61
  _: 'rascunho',
61
62
  tooltip: 'Esta página está em construção.'
63
+ },
64
+ new: {
65
+ _: 'novo',
66
+ tooltip: 'Esta página é nova.',
67
+ tooltipVersion: 'Novo na {version}'
68
+ }
69
+ },
70
+
71
+ version: {
72
+ status: {
73
+ released: 'publicada',
74
+ draft: 'rascunho',
75
+ deprecated: 'obsoleta'
62
76
  }
63
77
  },
64
78
 
package/src/i18n/path.js CHANGED
@@ -73,6 +73,19 @@ export function splitDotPathSegments (dotPath) {
73
73
  return normalized.split('.').filter(Boolean)
74
74
  }
75
75
 
76
+ function splitI18nPathSegments (path) {
77
+ if (Array.isArray(path)) {
78
+ return normalizeSegments(path)
79
+ }
80
+
81
+ const normalized = String(path || '').trim()
82
+ if (normalized.includes('/')) {
83
+ return splitRoutePathSegments(normalized)
84
+ }
85
+
86
+ return splitDotPathSegments(normalized)
87
+ }
88
+
76
89
  export function routeTitleI18nPath (routePath) {
77
90
  return buildI18nPath('_', ...splitRoutePathSegments(routePath), '_')
78
91
  }
@@ -82,11 +95,11 @@ export function routeSubpageSourceI18nPath (routePath, subpage = 'overview') {
82
95
  }
83
96
 
84
97
  export function pageTitleI18nPath (basePath) {
85
- return buildI18nPath('_', ...splitDotPathSegments(basePath), '_')
98
+ return buildI18nPath('_', ...splitI18nPathSegments(basePath), '_')
86
99
  }
87
100
 
88
101
  export function pageValueI18nPath (absolutePath, key = 'source') {
89
- return buildI18nPath('_', ...splitDotPathSegments(absolutePath), key)
102
+ return buildI18nPath('_', ...splitI18nPathSegments(absolutePath), key)
90
103
  }
91
104
 
92
105
  export function namespacedLabelI18nPath (book, nodePath) {
package/src/index.js CHANGED
@@ -27,7 +27,7 @@
27
27
  * @param {string} config.branding.name - Project name displayed in sidebar
28
28
  * @param {string} config.branding.version - Version label
29
29
  * @param {string} [config.branding.description] - Project description (used in llms.txt)
30
- * @param {string[]} [config.branding.versions] - Available versions for dropdown
30
+ * @param {Array<string|Object>} [config.branding.versions] - Available versions for dropdown. Current docs keep unprefixed routes; archived versions can live in src/pages/.old/<version>/ and use /<version>/ route prefixes. Version objects may set released:false/status:'draft', status:'deprecated'/deprecated:true, or badge:{label,color,textColor} for selector badges.
31
31
  * @param {Object} config.links - External links
32
32
  * @param {string} [config.links.github] - GitHub repository URL
33
33
  * @param {string} [config.links.discussions] - GitHub discussions URL
@@ -111,7 +111,7 @@ export function createDocsector (config = {}) {
111
111
  logo: '/images/logo.png',
112
112
  name: 'My Project',
113
113
  version: 'v0.0.1',
114
- versions: ['v0.0.1'],
114
+ versions: [{ id: 'v0.0.1', current: true, released: false }],
115
115
  ...config.branding
116
116
  },
117
117
 
@@ -59,7 +59,7 @@ import { useMeta, colors } from 'quasar'
59
59
 
60
60
  import DMenu from '../components/DMenu.vue'
61
61
  import docsectorConfig from 'docsector.config.js'
62
- import { allBooks } from 'virtual:docsector-books'
62
+ import { allBooks, booksByVersion } from 'virtual:docsector-books'
63
63
  import { pageTitleI18nPath } from '../i18n/path'
64
64
 
65
65
  defineOptions({ name: 'LayoutDefault' })
@@ -178,8 +178,20 @@ const getBookTabStyle = (book) => {
178
178
  }
179
179
  }
180
180
 
181
+ const activeVersionId = computed(() => {
182
+ return route.matched?.[0]?.meta?.version ?? route.meta?.version ?? null
183
+ })
184
+
185
+ const activeVersionBooks = computed(() => {
186
+ if (activeVersionId.value && booksByVersion?.[activeVersionId.value]?.allBooks) {
187
+ return booksByVersion[activeVersionId.value].allBooks
188
+ }
189
+
190
+ return allBooks || []
191
+ })
192
+
181
193
  const sortedBooks = computed(() => {
182
- return [...(allBooks || [])]
194
+ return [...activeVersionBooks.value]
183
195
  .filter(book => book && typeof book.id === 'string' && book.id.length > 0)
184
196
  .sort((a, b) => {
185
197
  const orderA = Number.isFinite(a.order) ? a.order : Number.MAX_SAFE_INTEGER
@@ -261,10 +273,12 @@ function openSettingsDialog () {
261
273
 
262
274
  function getFirstRoutePathByBook (bookId) {
263
275
  const routes = router.options?.routes || []
276
+ const versionId = activeVersionId.value
264
277
  let fallbackPath = null
265
278
 
266
279
  for (const topRoute of routes) {
267
280
  if (!topRoute || typeof topRoute.path !== 'string') continue
281
+ if (versionId && topRoute.meta?.version !== versionId) continue
268
282
  if ((topRoute.meta?.book ?? topRoute.meta?.type) !== bookId) continue
269
283
 
270
284
  const children = Array.isArray(topRoute.children) ? topRoute.children : []
@@ -0,0 +1,7 @@
1
+ ## Archived Version
2
+
3
+ This page is a minimal archived `v0.x` fixture used to validate Docsector Reader version switching.
4
+
5
+ ## Current Behavior
6
+
7
+ Selecting `v0.x` in the sidebar keeps the active book and page when an archived equivalent exists, then serves this Markdown from `src/pages/.old/v0.x`.
@@ -0,0 +1,7 @@
1
+ ## Versao Arquivada
2
+
3
+ Esta pagina e um fixture minimo arquivado `v0.x` usado para validar a troca de versoes do Docsector Reader.
4
+
5
+ ## Comportamento Atual
6
+
7
+ Ao selecionar `v0.x` no menu lateral, o leitor preserva o book e a pagina ativos quando existe um equivalente arquivado, entao serve este Markdown a partir de `src/pages/.old/v0.x`.
@@ -0,0 +1,12 @@
1
+ import { defineBook } from '../../../index.js'
2
+
3
+ export default defineBook({
4
+ id: 'guide',
5
+ label: 'Guide',
6
+ icon: 'history_edu',
7
+ order: 1,
8
+ color: {
9
+ active: 'white',
10
+ inactive: 'white'
11
+ }
12
+ })
@@ -0,0 +1,28 @@
1
+ export default {
2
+ '/getting-started': {
3
+ config: {
4
+ icon: 'history',
5
+ status: 'done',
6
+ meta: {
7
+ description: {
8
+ 'en-US': 'Getting Started - Archived v0.x documentation of Docsector Reader',
9
+ 'pt-BR': 'Comecando - Documentacao arquivada v0.x do Docsector Reader'
10
+ }
11
+ },
12
+ book: 'guide',
13
+ menu: {
14
+ header: {
15
+ icon: 'history_edu',
16
+ label: 'Archived v0.x'
17
+ }
18
+ },
19
+ subpages: {
20
+ showcase: false
21
+ }
22
+ },
23
+ data: {
24
+ 'en-US': { title: 'Getting Started v0.x' },
25
+ 'pt-BR': { title: 'Comecando v0.x' }
26
+ }
27
+ }
28
+ }
@@ -9,10 +9,17 @@ branding: &#123;
9
9
  logo: '/images/logo.png', // Path to logo in public/
10
10
  name: 'My Project', // Project name shown in sidebar
11
11
  version: 'v1.0.0', // Current version badge
12
- versions: ['v1.0.0'] // Version dropdown options
12
+ versions: [
13
+ &#123; id: 'v1.0.0', current: true, released: false &#125;,
14
+ &#123; id: 'v0.x', released: true, status: 'deprecated' &#125;
15
+ ] // Version dropdown options
13
16
  &#125;
14
17
  ```
15
18
 
19
+ The current version keeps unprefixed routes such as `/guide/getting-started/overview/`. Archived major versions can live under `src/pages/.old/&#123;version&#125;/` using the same book registry and Markdown layout, and are exposed at `/<version>/...`, for example `/v0.x/guide/getting-started/overview/`.
20
+
21
+ Every version shows a release badge next to the version in the selector. Released versions default to `released`; versions with `released: false` or `status: 'draft'` default to `draft`; versions with `status: 'deprecated'` or `deprecated: true` default to `deprecated` in red. Use `badge: &#123; label, color, textColor &#125;` to customize the badge.
22
+
16
23
  The `logo` path is relative to the `public/` folder. Recommended size: **85×85px**.
17
24
 
18
25
  ## Links
@@ -84,7 +91,11 @@ export default &#123;
84
91
  logo: '/images/logo.png',
85
92
  name: 'Acme Docs',
86
93
  version: 'v2.1.0',
87
- versions: ['v2.1.0', 'v2.0.0', 'v1.0.0']
94
+ versions: [
95
+ &#123; id: 'v2.1.0', current: true, released: false &#125;,
96
+ &#123; id: 'v2.0.0', released: true &#125;,
97
+ &#123; id: 'v1.0.0', released: true, status: 'deprecated' &#125;
98
+ ]
88
99
  &#125;,
89
100
  links: &#123;
90
101
  github: 'https://github.com/acme/acme',
@@ -9,10 +9,17 @@ branding: &#123;
9
9
  logo: '/images/logo.png', // Caminho do logo em public/
10
10
  name: 'Meu Projeto', // Nome exibido na sidebar
11
11
  version: 'v1.0.0', // Badge de versão atual
12
- versions: ['v1.0.0'] // Opções do dropdown de versão
12
+ versions: [
13
+ &#123; id: 'v1.0.0', current: true, released: false &#125;,
14
+ &#123; id: 'v0.x', released: true, status: 'deprecated' &#125;
15
+ ] // Opções do dropdown de versão
13
16
  &#125;
14
17
  ```
15
18
 
19
+ A versão atual mantém rotas sem prefixo, como `/guide/getting-started/overview/`. Versões major arquivadas podem ficar em `src/pages/.old/&#123;version&#125;/` usando o mesmo layout de book registry e Markdown, e são expostas em `/<version>/...`, por exemplo `/v0.x/guide/getting-started/overview/`.
20
+
21
+ Toda versão mostra um badge de release ao lado da versão no seletor. Versões lançadas usam `released` por padrão; versões com `released: false` ou `status: 'draft'` usam `draft`; versões com `status: 'deprecated'` ou `deprecated: true` usam `deprecated` em vermelho. Use `badge: &#123; label, color, textColor &#125;` para customizar o badge.
22
+
16
23
  O caminho do `logo` é relativo à pasta `public/`. Tamanho recomendado: **85×85px**.
17
24
 
18
25
  ## Links
@@ -84,7 +91,11 @@ export default &#123;
84
91
  logo: '/images/logo.png',
85
92
  name: 'Acme Docs',
86
93
  version: 'v2.1.0',
87
- versions: ['v2.1.0', 'v2.0.0', 'v1.0.0']
94
+ versions: [
95
+ &#123; id: 'v2.1.0', current: true, released: false &#125;,
96
+ &#123; id: 'v2.0.0', released: true &#125;,
97
+ &#123; id: 'v1.0.0', released: true, status: 'deprecated' &#125;
98
+ ]
88
99
  &#125;,
89
100
  links: &#123;
90
101
  github: 'https://github.com/acme/acme',
@@ -8,7 +8,8 @@ Documentation pages are defined in split registries such as `src/pages/guide.ind
8
8
  '/my-page': &#123;
9
9
  config: &#123;
10
10
  icon: 'description',
11
- status: 'done',
11
+ status: 'new',
12
+ version: 'v2.1.0',
12
13
  book: 'guide',
13
14
  menu: &#123;&#125;,
14
15
  subpages: &#123; showcase: false &#125;
@@ -23,7 +24,8 @@ Documentation pages are defined in split registries such as `src/pages/guide.ind
23
24
  ## Config Properties
24
25
 
25
26
  - **book** — Route prefix: `'guide'`, `'manual'`, or `'API'` (legacy `type` is still supported)
26
- - **status** — Page status: `'done'`, `'draft'`, or `'empty'`
27
+ - **status** — Page status: `'done'`, `'draft'`, `'empty'`, or `'new'`; `new` is shown in green
28
+ - **version** — Optional version where the page was introduced, shown under the last updated date as `New in: ...` (for example, `'v2.1.0'`)
27
29
  - **icon** — Material Design icon name shown in the sidebar
28
30
  - **menu** — Object controlling menu display (header, subheader, separator)
29
31
  - **subpages** — Enable additional tabs: `showcase`, `vs`
@@ -83,3 +85,5 @@ Routes are automatically generated from the page registry. A page with path `/my
83
85
  - `/guide/my-page/overview` — Main content tab
84
86
  - `/guide/my-page/showcase` — Showcase tab (if enabled)
85
87
  - `/guide/my-page/vs` — Comparison tab (if enabled)
88
+
89
+ Archived major versions use the same structure under `src/pages/.old/&#123;version&#125;/`. A page registered in `src/pages/.old/v0.x/guide.index.js` produces `/v0.x/guide/my-page/overview` while the current version remains `/guide/my-page/overview`.
@@ -8,7 +8,8 @@ As páginas de documentação são definidas em registros separados, como `src/p
8
8
  '/minha-pagina': &#123;
9
9
  config: &#123;
10
10
  icon: 'description',
11
- status: 'done',
11
+ status: 'new',
12
+ version: 'v2.1.0',
12
13
  book: 'guide',
13
14
  menu: &#123;&#125;,
14
15
  subpages: &#123; showcase: false &#125;
@@ -23,7 +24,8 @@ As páginas de documentação são definidas em registros separados, como `src/p
23
24
  ## Propriedades do Config
24
25
 
25
26
  - **book** — Prefixo da rota: `'guide'`, `'manual'` ou `'API'` (compatível com `type` legado)
26
- - **status** — Status da página: `'done'`, `'draft'` ou `'empty'`
27
+ - **status** — Status da página: `'done'`, `'draft'`, `'empty'` ou `'new'`; `new` é exibido em verde
28
+ - **version** — Versão opcional em que a página foi introduzida, exibida abaixo da data de última atualização como `Novo em: ...` (por exemplo, `'v2.1.0'`)
27
29
  - **icon** — Nome do ícone Material Design exibido no menu lateral
28
30
  - **menu** — Objeto controlando exibição do menu (header, subheader, separator)
29
31
  - **subpages** — Ativar abas adicionais: `showcase`, `vs`
@@ -83,3 +85,5 @@ Rotas são geradas automaticamente a partir do registro de páginas. Uma página
83
85
  - `/guide/my-page/overview` — Aba de conteúdo principal
84
86
  - `/guide/my-page/showcase` — Aba de demonstração (se habilitada)
85
87
  - `/guide/my-page/vs` — Aba de comparação (se habilitada)
88
+
89
+ Versões major arquivadas usam a mesma estrutura em `src/pages/.old/&#123;version&#125;/`. Uma página registrada em `src/pages/.old/v0.x/guide.index.js` produz `/v0.x/guide/my-page/overview`, enquanto a versão atual continua em `/guide/my-page/overview`.