@docsector/docsector-reader 0.1.3 → 0.2.1

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.
@@ -1,7 +1,7 @@
1
1
  <script setup>
2
2
  import { watch } from 'vue'
3
3
 
4
- import useNavigator from 'src/composables/useNavigator'
4
+ import useNavigator from '../composables/useNavigator'
5
5
 
6
6
  const props = defineProps({
7
7
  id: {
@@ -4,7 +4,7 @@ import { useRoute, useRouter } from 'vue-router'
4
4
  import { useQuasar, scroll, openURL } from 'quasar'
5
5
  import { useI18n } from 'vue-i18n'
6
6
 
7
- import tags from 'src/i18n/tags.hjson'
7
+ import tags from '@docsector/tags'
8
8
  import DMenuItem from './DMenuItem.vue'
9
9
  import docsectorConfig from 'docsector.config.js'
10
10
 
@@ -35,8 +35,8 @@ const searchTerm = (term) => {
35
35
  const locale = $q.localStorage.getItem('setting.language')
36
36
  founds.value = []
37
37
 
38
- for (const [index, items] of items.value.entries()) {
39
- searchTermIterate(items, term, locale)
38
+ for (const [index, group] of items.value.entries()) {
39
+ searchTermIterate(group, term, locale)
40
40
  }
41
41
  } else {
42
42
  founds.value = false
@@ -54,7 +54,7 @@ const searchTermIterate = (items, term, locale) => {
54
54
  founds.value[path] = false
55
55
 
56
56
  // @ search in i18n/tags.hjson
57
- if (tags[locale] && tags[locale].length > 0) {
57
+ if (tags[locale] && Object.keys(tags[locale]).length > 0) {
58
58
  founds.value[path] = tags[locale][path]?.indexOf(term) !== -1
59
59
  if (founds.value[path] === false && locale !== 'en-US') {
60
60
  founds.value[path] = tags['en-US'][path]?.indexOf(term) !== -1
@@ -4,10 +4,10 @@ import { useStore } from 'vuex'
4
4
  import { useRoute, useRouter } from 'vue-router'
5
5
  import { useQuasar } from 'quasar'
6
6
 
7
- import useNavigator from 'src/composables/useNavigator'
7
+ import useNavigator from '../composables/useNavigator'
8
8
 
9
- import DPageAnchor from 'components/DPageAnchor.vue'
10
- import DPageMeta from 'components/DPageMeta.vue'
9
+ import DPageAnchor from './DPageAnchor.vue'
10
+ import DPageMeta from './DPageMeta.vue'
11
11
 
12
12
  const store = useStore()
13
13
  const router = useRouter()
@@ -4,7 +4,7 @@ import { useStore } from 'vuex'
4
4
  import { useQuasar } from 'quasar'
5
5
  import { useRoute } from "vue-router";
6
6
 
7
- import useNavigator from 'src/composables/useNavigator'
7
+ import useNavigator from '../composables/useNavigator'
8
8
 
9
9
  const store = useStore()
10
10
  const $q = useQuasar()
@@ -15,7 +15,7 @@ import { useColorize } from 'q-colorize-mixin'
15
15
  import { dom } from 'quasar'
16
16
  const { offset } = dom
17
17
 
18
- import './QZoom.styl'
18
+ import './QZoom.sass'
19
19
 
20
20
  // @
21
21
  export default {
@@ -0,0 +1,43 @@
1
+ $box-shadow: 1px 1px 7px 1px rgba(0,0,0,.2) !default
2
+
3
+ .q-zoom
4
+ position: relative
5
+ padding: 0
6
+ margin: 0
7
+
8
+ &__zoom-in
9
+ cursor: zoom-in
10
+
11
+ &__zoom-out
12
+ cursor: zoom-out
13
+
14
+ &__overlay
15
+ position: fixed
16
+ transition: all .5s linear
17
+ left: 0
18
+ top: 0
19
+ width: 100%
20
+ height: 100%
21
+ background-color: transparent
22
+ padding: 0
23
+ margin: 0
24
+ z-index: 6000
25
+
26
+ &__content
27
+ position: relative
28
+ display: block
29
+ transition: all .5s cubic-bezier(.2,0,.2,1)
30
+ text-align: center
31
+ vertical-align: middle
32
+ width: 100%
33
+ height: 0
34
+ max-width: 100%
35
+ max-height: 100%
36
+ overflow: hidden
37
+
38
+ &__no-center
39
+ text-align: unset
40
+ vertical-align: unset
41
+
42
+ &__no-scroll
43
+ overflow: hidden
@@ -0,0 +1,160 @@
1
+ /**
2
+ * Docsector Reader — i18n Message Builder
3
+ *
4
+ * Extracts the markdown-to-i18n processing logic so consumer projects
5
+ * can call it with their own import.meta.glob results.
6
+ *
7
+ * Usage in consumer's src/i18n/index.js:
8
+ *
9
+ * import { buildMessages } from '@docsector/docsector-reader/i18n'
10
+ * import boot from 'pages/boot'
11
+ * import pages from 'pages'
12
+ *
13
+ * const langModules = import.meta.glob('./languages/*.hjson', { eager: true })
14
+ * const mdModules = import.meta.glob('../pages/⁣**​/⁣*.md', { eager: true, query: '?raw', import: 'default' })
15
+ *
16
+ * export default buildMessages({ langModules, mdModules, pages, boot })
17
+ */
18
+
19
+ /**
20
+ * Escape characters that conflict with vue-i18n message syntax.
21
+ *
22
+ * @param {string} source - Raw markdown string
23
+ * @returns {string} Escaped string safe for vue-i18n
24
+ */
25
+ export function filter (source) {
26
+ const regex1 = /{/gm
27
+ const regex2 = /}/gm
28
+ const regex3 = /([@|])+/gm
29
+
30
+ source = source
31
+ .replace(regex1, '&#123;')
32
+ .replace(regex2, '&#125;')
33
+ .replace(regex3, "{'$&'}")
34
+
35
+ return source
36
+ }
37
+
38
+ /**
39
+ * Build complete i18n messages from HJSON locale files and Markdown page content.
40
+ *
41
+ * @param {Object} options
42
+ * @param {Object} options.langModules - Result of import.meta.glob('./languages/*.hjson', { eager: true })
43
+ * @param {Object} options.mdModules - Result of import.meta.glob('../pages/**​/*.md', { eager: true, query: '?raw', import: 'default' })
44
+ * @param {Object} options.pages - Page registry from pages/index.js
45
+ * @param {Object} options.boot - Boot meta from pages/boot.js
46
+ * @param {string[]} [options.langs] - Language codes to process (auto-detected from langModules if omitted)
47
+ * @returns {Object} Complete i18n messages object keyed by locale
48
+ */
49
+ export function buildMessages ({ langModules, mdModules, pages, boot, langs }) {
50
+ // Auto-detect languages from HJSON files if not provided
51
+ if (!langs) {
52
+ langs = Object.keys(langModules).map(key => {
53
+ // key is like './languages/en-US.hjson' — extract 'en-US'
54
+ const match = key.match(/\/([^/]+)\.hjson$/)
55
+ return match ? match[1] : null
56
+ }).filter(Boolean)
57
+ }
58
+
59
+ const i18n = {}
60
+
61
+ function load (topPage, path, subpage, lang) {
62
+ const key = `../pages/${topPage}/${path}.${subpage}.${lang}.md`
63
+ const content = mdModules[key]
64
+
65
+ if (!content) {
66
+ console.warn(`[i18n] Missing markdown: ${key}`)
67
+ return ''
68
+ }
69
+
70
+ const source = filter(typeof content === 'string' ? content : String(content))
71
+ return source
72
+ }
73
+
74
+ // @ Iterate langs
75
+ for (const lang of langs) {
76
+ // Load HJSON language file
77
+ const langKey = `./languages/${lang}.hjson`
78
+ i18n[lang] = langModules[langKey]?.default || langModules[langKey] || {}
79
+
80
+ // @ Iterate pages
81
+ for (const [key, page] of Object.entries(pages)) {
82
+ const path = key.slice(1)
83
+
84
+ const config = page.config
85
+ const data = page.data
86
+ const meta = page.meta || boot.meta
87
+
88
+ const topPage = config?.type ?? 'manual'
89
+
90
+ // ---
91
+
92
+ const _ = path.split('/').reduce((accumulator, current) => {
93
+ let node = accumulator[current]
94
+
95
+ // Set object if not exists
96
+ if (node === undefined) {
97
+ accumulator[current] = {}
98
+ node = accumulator[current]
99
+ }
100
+
101
+ // @ Set metadata
102
+ // title
103
+ if (node._ === undefined) {
104
+ node._ = data[lang]?.title || data['*']?.title
105
+ }
106
+
107
+ if (config === null) {
108
+ return node
109
+ }
110
+
111
+ // Set subpages sources if not exists
112
+ if (node.overview === undefined) {
113
+ node.overview = {
114
+ _translations: meta[lang]?.overview?._translations,
115
+ _sections: meta[lang]?.overview?._sections,
116
+ source: ''
117
+ }
118
+ }
119
+ if (config.subpages?.showcase && node.showcase === undefined) {
120
+ node.showcase = {
121
+ _translations: meta[lang]?.showcase?._translations,
122
+ _sections: meta[lang]?.showcase?._sections,
123
+ source: ''
124
+ }
125
+ }
126
+ if (config.subpages?.vs && node.vs === undefined) {
127
+ node.vs = {
128
+ _translations: meta[lang]?.vs?._translations,
129
+ _sections: meta[lang]?.vs?._sections,
130
+ source: ''
131
+ }
132
+ }
133
+
134
+ return node
135
+ }, i18n[lang]._[topPage])
136
+
137
+ // ---
138
+
139
+ if (config === null || config.status === 'empty') {
140
+ continue
141
+ }
142
+
143
+ // @ Subpages
144
+ // Overview
145
+ _.overview.source = load(topPage, path, 'overview', lang)
146
+ // showcase
147
+ if (config.subpages?.showcase === true) {
148
+ _.showcase.source = load(topPage, path, 'showcase', lang)
149
+ }
150
+ // Vs
151
+ if (config.subpages?.vs === true) {
152
+ _.vs.source = load(topPage, path, 'vs', lang)
153
+ }
154
+ }
155
+ }
156
+
157
+ return i18n
158
+ }
159
+
160
+ export default buildMessages
package/src/i18n/index.js CHANGED
@@ -1,3 +1,6 @@
1
+ // @ Import i18n message builder
2
+ import { buildMessages } from './helpers'
3
+
1
4
  // @ Import language HJSON files (Vite-compatible eager import)
2
5
  const langModules = import.meta.glob('./languages/*.hjson', { eager: true })
3
6
  // @ Import markdown files (Vite-compatible eager import as raw strings)
@@ -7,120 +10,4 @@ const mdModules = import.meta.glob('../pages/**/*.md', { eager: true, query: '?r
7
10
  import boot from 'pages/boot'
8
11
  import pages from 'pages'
9
12
 
10
- const langs = [
11
- 'en-US',
12
- 'pt-BR'
13
- ]
14
- const i18n = {}
15
-
16
- function filter (source) {
17
- const regex1 = /{/gm
18
- const regex2 = /}/gm
19
- const regex3 = /([@|])+/gm
20
-
21
- source = source
22
- .replace(regex1, '&#123;')
23
- .replace(regex2, '&#125;')
24
- .replace(regex3, "{'$&'}")
25
-
26
- return source
27
- }
28
-
29
- function load (topPage, path, subpage, lang) {
30
- const key = `../pages/${topPage}/${path}.${subpage}.${lang}.md`
31
- const content = mdModules[key]
32
-
33
- if (!content) {
34
- console.warn(`[i18n] Missing markdown: ${key}`)
35
- return ''
36
- }
37
-
38
- const source = filter(typeof content === 'string' ? content : String(content))
39
-
40
- return source
41
- }
42
-
43
- // @ Iterate langs
44
- for (const lang of langs) {
45
- // Load HJSON language file
46
- const langKey = `./languages/${lang}.hjson`
47
- i18n[lang] = langModules[langKey]?.default || langModules[langKey] || {}
48
-
49
- // @ Iterate pages
50
- for (const [key, page] of Object.entries(pages)) {
51
- const path = key.slice(1)
52
-
53
- const config = page.config
54
- const data = page.data
55
- const meta = page.meta || boot.meta
56
-
57
- const topPage = config?.type ?? 'manual'
58
-
59
- // ---
60
-
61
- const _ = path.split('/').reduce((accumulator, current) => {
62
- let node = accumulator[current]
63
-
64
- // Set object if not exists
65
- if (node === undefined) {
66
- accumulator[current] = {}
67
- node = accumulator[current]
68
- }
69
-
70
- // @ Set metadata
71
- // title
72
- if (node._ === undefined) {
73
- node._ = data[lang]?.title || data['*']?.title
74
- }
75
-
76
- if (config === null) {
77
- return node
78
- }
79
-
80
- // Set subpages sources if not exists
81
- if (node.overview === undefined) {
82
- node.overview = {
83
- _translations: meta[lang]?.overview?._translations,
84
- _sections: meta[lang]?.overview?._sections,
85
- source: ''
86
- }
87
- }
88
- if (config.subpages?.showcase && node.showcase === undefined) {
89
- node.showcase = {
90
- _translations: meta[lang]?.showcase?._translations,
91
- _sections: meta[lang]?.showcase?._sections,
92
- source: ''
93
- }
94
- }
95
- if (config.subpages?.vs && node.vs === undefined) {
96
- node.vs = {
97
- _translations: meta[lang]?.vs?._translations,
98
- _sections: meta[lang]?.vs?._sections,
99
- source: ''
100
- }
101
- }
102
-
103
- return node
104
- }, i18n[lang]._[topPage])
105
-
106
- // ---
107
-
108
- if (config === null || config.status === 'empty') {
109
- continue
110
- }
111
-
112
- // @ Subpages
113
- // Overview
114
- _.overview.source = load(topPage, path, 'overview', lang)
115
- // showcase
116
- if (config.subpages?.showcase === true) {
117
- _.showcase.source = load(topPage, path, 'showcase', lang)
118
- }
119
- // Vs
120
- if (config.subpages?.vs === true) {
121
- _.vs.source = load(topPage, path, 'vs', lang)
122
- }
123
- }
124
- }
125
-
126
- export default i18n
13
+ export default buildMessages({ langModules, mdModules, pages, boot })
@@ -33,7 +33,7 @@ import { useRoute, useRouter } from 'vue-router'
33
33
  import { useStore } from 'vuex'
34
34
  import { useI18n } from 'vue-i18n'
35
35
 
36
- import DMenu from 'components/DMenu.vue'
36
+ import DMenu from '../components/DMenu.vue'
37
37
  import docsectorConfig from 'docsector.config.js'
38
38
 
39
39
  defineOptions({ name: 'LayoutDefault' })
@@ -10,50 +10,68 @@ Docsector Reader is a **documentation rendering engine** built with Vue 3, Quasa
10
10
 
11
11
  ## Installation
12
12
 
13
+ Scaffold a new documentation project with the CLI:
14
+
13
15
  ```bash
14
- npx degit docsector/docsector-reader my-docs
16
+ npx @docsector/docsector-reader init my-docs
15
17
  cd my-docs
16
18
  npm install
17
19
  ```
18
20
 
21
+ This creates a ready-to-use project with all necessary configuration files, a sample page registry, and i18n setup.
22
+
19
23
  ## Development Server
20
24
 
21
25
  Start the dev server with hot-reload:
22
26
 
23
27
  ```bash
24
- npx quasar dev
28
+ npx docsector dev
25
29
  ```
26
30
 
27
31
  The documentation site will be available at **http://localhost:8181**.
28
32
 
33
+ You can also specify a custom port:
34
+
35
+ ```bash
36
+ npx docsector dev --port 3000
37
+ ```
38
+
29
39
  ## Production Build
30
40
 
31
41
  Build an optimized SPA for deployment:
32
42
 
33
43
  ```bash
34
- npx quasar build
44
+ npx docsector build
35
45
  ```
36
46
 
37
47
  The output is placed in `dist/spa/` — ready to deploy to any static hosting.
38
48
 
49
+ To preview the production build locally:
50
+
51
+ ```bash
52
+ npx docsector serve
53
+ ```
54
+
39
55
  ## Project Structure
40
56
 
41
- The project follows a standard Quasar v2 layout with documentation-specific conventions:
57
+ After `init`, your project will have this structure:
42
58
 
43
- - `docsector.config.js` — Branding, links, languages
59
+ - `docsector.config.js` — Branding, links, languages, GitHub config
60
+ - `quasar.config.js` — Thin wrapper using `createQuasarConfig()` from the package
61
+ - `index.html` — HTML entry point with title and meta tags
44
62
  - `src/pages/index.js` — Page registry (routes and metadata)
45
63
  - `src/pages/guide/` — Guide-type pages (Markdown files)
46
64
  - `src/pages/manual/` — Manual-type pages (Markdown files)
47
- - `src/components/`Docsector Vue components
48
- - `src/composables/`Vue composables (useNavigator)
49
- - `src/store/` — Vuex 4 modules
50
- - `src/i18n/` — Language files (.hjson) and loader
51
- - `src/layouts/`DefaultLayout and SystemLayout
52
- - `src/boot/` — Boot files (store, i18n, QZoom, axios)
65
+ - `src/i18n/index.js`i18n loader using `buildMessages()` from the package
66
+ - `src/i18n/tags.hjson`Search keywords per route and locale
67
+ - `public/` — Static assets (logo, favicon, images)
68
+
69
+ The rendering engine (components, layouts, router, store, composables) lives inside the `@docsector/docsector-reader` package you only maintain your content and configuration.
53
70
 
54
71
  ## Next Steps
55
72
 
56
73
  - Configure your project branding in **docsector.config.js**
57
74
  - Define your pages in **src/pages/index.js**
58
75
  - Write your documentation in **Markdown**
76
+ - Add search keywords in **src/i18n/tags.hjson**
59
77
  - Customize themes and appearance
@@ -10,50 +10,68 @@ Docsector Reader é um **motor de renderização de documentação** construído
10
10
 
11
11
  ## Instalação
12
12
 
13
+ Crie um novo projeto de documentação com o CLI:
14
+
13
15
  ```bash
14
- npx degit docsector/docsector-reader my-docs
16
+ npx @docsector/docsector-reader init my-docs
15
17
  cd my-docs
16
18
  npm install
17
19
  ```
18
20
 
21
+ Isso cria um projeto pronto para uso com todos os arquivos de configuração, um registro de páginas de exemplo e setup de i18n.
22
+
19
23
  ## Servidor de Desenvolvimento
20
24
 
21
25
  Inicie o servidor dev com hot-reload:
22
26
 
23
27
  ```bash
24
- npx quasar dev
28
+ npx docsector dev
25
29
  ```
26
30
 
27
31
  O site de documentação estará disponível em **http://localhost:8181**.
28
32
 
33
+ Você também pode especificar uma porta personalizada:
34
+
35
+ ```bash
36
+ npx docsector dev --port 3000
37
+ ```
38
+
29
39
  ## Build de Produção
30
40
 
31
41
  Gere um SPA otimizado para deploy:
32
42
 
33
43
  ```bash
34
- npx quasar build
44
+ npx docsector build
35
45
  ```
36
46
 
37
47
  O output fica em `dist/spa/` — pronto para deploy em qualquer hosting estático.
38
48
 
49
+ Para visualizar a build de produção localmente:
50
+
51
+ ```bash
52
+ npx docsector serve
53
+ ```
54
+
39
55
  ## Estrutura do Projeto
40
56
 
41
- O projeto segue o layout padrão do Quasar v2 com convenções específicas para documentação:
57
+ Após o `init`, seu projeto terá esta estrutura:
42
58
 
43
- - `docsector.config.js` — Branding, links, idiomas
59
+ - `docsector.config.js` — Branding, links, idiomas, config do GitHub
60
+ - `quasar.config.js` — Wrapper fino usando `createQuasarConfig()` do pacote
61
+ - `index.html` — Ponto de entrada HTML com título e meta tags
44
62
  - `src/pages/index.js` — Registro de páginas (rotas e metadata)
45
63
  - `src/pages/guide/` — Páginas tipo guia (arquivos Markdown)
46
64
  - `src/pages/manual/` — Páginas tipo manual (arquivos Markdown)
47
- - `src/components/`Componentes Vue do Docsector
48
- - `src/composables/`Composables Vue (useNavigator)
49
- - `src/store/` — Módulos Vuex 4
50
- - `src/i18n/` — Arquivos de idioma (.hjson) e loader
51
- - `src/layouts/`DefaultLayout e SystemLayout
52
- - `src/boot/` — Boot files (store, i18n, QZoom, axios)
65
+ - `src/i18n/index.js`Loader i18n usando `buildMessages()` do pacote
66
+ - `src/i18n/tags.hjson`Palavras-chave de busca por rota e idioma
67
+ - `public/` — Assets estáticos (logo, favicon, imagens)
68
+
69
+ O motor de renderização (componentes, layouts, router, store, composables) fica dentro do pacote `@docsector/docsector-reader` você só mantém seu conteúdo e configuração.
53
70
 
54
71
  ## Próximos Passos
55
72
 
56
73
  - Configure o branding do seu projeto em **docsector.config.js**
57
74
  - Defina suas páginas em **src/pages/index.js**
58
75
  - Escreva sua documentação em **Markdown**
76
+ - Adicione palavras-chave de busca em **src/i18n/tags.hjson**
59
77
  - Personalize temas e aparência