feat: новый дизайн документации — шаблон, генератор, CSS, md_in_html, версия 5.1.2
This commit is contained in:
@@ -3,7 +3,7 @@ NUBES_API_ENDPOINT="https://lk-api-gateway-test.ngcloud.ru/api/v1/svc"
|
||||
TOKEN_FILE="secrets/test.token"
|
||||
|
||||
# Version
|
||||
VERSION="5.2.0"
|
||||
VERSION="5.1.2"
|
||||
|
||||
# Docs generation — ONLY from docs_gen/<stand>/ (never from docs/)
|
||||
DOCS_GEN_DIR="provider/docs_gen/test"
|
||||
|
||||
@@ -21,15 +21,21 @@ var CloudOutputByServiceID = map[int]types.CloudOutputSnapshot{}
|
||||
// ResourceDocs генерирует полный набор .md файлов для одного сервиса.
|
||||
func ResourceDocs(docsDir string, spec types.ServiceSpec, version string, apiEndpoint string, providerSource string) {
|
||||
base := spec.Name
|
||||
nav := fmt.Sprintf("[Manual](%s.md) | [Create params](%s_params_create.md) | [Modify params](%s_params_modify.md) | [Output params](%s_outputs.md) | [Operations](%s_ops.md) | [Example](%s_example.md)", base, base, base, base, base, base)
|
||||
|
||||
WriteFile(filepath.Join(docsDir, base+".md"), buildManualPage(spec, nav))
|
||||
WriteFile(filepath.Join(docsDir, base+"_example.md"), buildExamplePage(spec, nav, version, apiEndpoint, providerSource))
|
||||
WriteFile(filepath.Join(docsDir, base+"_params_create.md"), buildCreateParamsPage(spec, nav))
|
||||
WriteFile(filepath.Join(docsDir, base+"_params_modify.md"), buildModifyParamsPage(spec, nav))
|
||||
WriteFile(filepath.Join(docsDir, base+"_outputs.md"), buildOutputsPage(spec, nav))
|
||||
WriteFile(filepath.Join(docsDir, base+"_ops.md"), buildOpsPage(spec, nav, docsDir))
|
||||
WriteFile(filepath.Join(docsDir, base+"_params.md"), buildParamsLandingPage(spec, nav))
|
||||
navManual := fmt.Sprintf("**Manual** · [Create params](%s_params_create.md) · [Modify params](%s_params_modify.md) · [Output params](%s_outputs.md) · [Operations](%s_ops.md) · [Example](%s_example.md)", base, base, base, base, base)
|
||||
navCreate := fmt.Sprintf("[Manual](%s.md) · **Create params** · [Modify params](%s_params_modify.md) · [Output params](%s_outputs.md) · [Operations](%s_ops.md) · [Example](%s_example.md)", base, base, base, base, base)
|
||||
navModify := fmt.Sprintf("[Manual](%s.md) · [Create params](%s_params_create.md) · **Modify params** · [Output params](%s_outputs.md) · [Operations](%s_ops.md) · [Example](%s_example.md)", base, base, base, base, base)
|
||||
navOutputs := fmt.Sprintf("[Manual](%s.md) · [Create params](%s_params_create.md) · [Modify params](%s_params_modify.md) · **Output params** · [Operations](%s_ops.md) · [Example](%s_example.md)", base, base, base, base, base)
|
||||
navOps := fmt.Sprintf("[Manual](%s.md) · [Create params](%s_params_create.md) · [Modify params](%s_params_modify.md) · [Output params](%s_outputs.md) · **Operations** · [Example](%s_example.md)", base, base, base, base, base)
|
||||
navExample := fmt.Sprintf("[Manual](%s.md) · [Create params](%s_params_create.md) · [Modify params](%s_params_modify.md) · [Output params](%s_outputs.md) · [Operations](%s_ops.md) · **Example**", base, base, base, base, base)
|
||||
|
||||
WriteFile(filepath.Join(docsDir, base+".md"), buildManualPage(spec, navManual))
|
||||
WriteFile(filepath.Join(docsDir, base+"_example.md"), buildExamplePage(spec, navExample, version, apiEndpoint, providerSource))
|
||||
WriteFile(filepath.Join(docsDir, base+"_params_create.md"), buildCreateParamsPage(spec, navCreate))
|
||||
WriteFile(filepath.Join(docsDir, base+"_params_modify.md"), buildModifyParamsPage(spec, navModify))
|
||||
WriteFile(filepath.Join(docsDir, base+"_outputs.md"), buildOutputsPage(spec, navOutputs))
|
||||
WriteFile(filepath.Join(docsDir, base+"_ops.md"), buildOpsPage(spec, navOps, docsDir))
|
||||
WriteFile(filepath.Join(docsDir, base+"_params.md"), buildParamsLandingPage(spec, navManual))
|
||||
|
||||
for _, srName := range CollectSubresources(spec) {
|
||||
srBase := fmt.Sprintf("%s_%s", base, Slug(srName))
|
||||
@@ -122,7 +128,7 @@ func buildHeader(spec types.ServiceSpec, nav string) string {
|
||||
if name == "" {
|
||||
name = spec.Name
|
||||
}
|
||||
return fmt.Sprintf("# Resource nubes_%s\n\nService ID: `%d`\n\nService Name: %s\n\n%s\n\n", spec.Name, spec.ServiceID, name, nav)
|
||||
return fmt.Sprintf("# Resource nubes_%s · Service ID: %d · Service Name: %s\n\n%s\n\n", spec.Name, spec.ServiceID, name, nav)
|
||||
}
|
||||
|
||||
func buildManualPage(spec types.ServiceSpec, nav string) string {
|
||||
|
||||
@@ -47,146 +47,181 @@
|
||||
padding-bottom: 0.3rem;
|
||||
}
|
||||
|
||||
/* Column sizing for resource tables */
|
||||
/* Widths based on real YAML data analysis, see docs/help/table-column-widths-analysis.md */
|
||||
.resource-table {
|
||||
.md-typeset .man-content {
|
||||
font-size: 0.62rem;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
/* Resource title + tabs: compact */
|
||||
.md-typeset .md-content__inner > h1:first-child {
|
||||
font-size: 0.77rem;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.md-typeset .md-content__inner > h1:first-child + p {
|
||||
font-size: 0.65rem;
|
||||
}
|
||||
|
||||
/* ---- ALL TABLE RULES — prefixed .md-typeset for MkDocs specificity ---- */
|
||||
.md-typeset .resource-table {
|
||||
width: 100%;
|
||||
table-layout: fixed;
|
||||
table-layout: auto;
|
||||
border-collapse: collapse;
|
||||
font-size: 0.82rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.resource-table th,
|
||||
.resource-table td {
|
||||
.md-typeset .resource-table th,
|
||||
.md-typeset .resource-table td {
|
||||
padding: 0.3rem 0.4rem;
|
||||
vertical-align: top;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
|
||||
font-size: 0.82rem;
|
||||
}
|
||||
|
||||
.resource-table thead th {
|
||||
.md-typeset .resource-table thead th {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 2;
|
||||
background: #fff;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/* ID column: useless to user, barely visible */
|
||||
.resource-table th:nth-child(1),
|
||||
.resource-table td:nth-child(1) {
|
||||
width: 2%;
|
||||
text-align: center;
|
||||
font-size: 0.72rem;
|
||||
white-space: nowrap;
|
||||
font-size: 0.58rem;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/* ---- MAIN TABLE: Code(18%) Type(5%) Default(auto) Descr(45%) Constr(30%) ---- */
|
||||
.md-typeset .resource-table tbody tr:nth-child(even) {
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.resource-table:not(.resource-table-nested) th:nth-child(2),
|
||||
.resource-table:not(.resource-table-nested) td:nth-child(2) {
|
||||
width: 18%;
|
||||
/* ID column: HIDDEN */
|
||||
.md-typeset .resource-table th:nth-child(1),
|
||||
.md-typeset .resource-table td:nth-child(1) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* ---- MAIN TABLE ---- */
|
||||
.md-typeset .resource-table:not(.resource-table-nested) th:nth-child(2),
|
||||
.md-typeset .resource-table:not(.resource-table-nested) td:nth-child(2) {
|
||||
width: 25%;
|
||||
min-width: 16ch;
|
||||
white-space: normal;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.resource-table:not(.resource-table-nested) td:nth-child(2) code {
|
||||
.md-typeset .resource-table:not(.resource-table-nested) td:nth-child(2) code {
|
||||
font-weight: 700;
|
||||
font-size: 0.82rem;
|
||||
}
|
||||
|
||||
.resource-table:not(.resource-table-nested) th:nth-child(3),
|
||||
.resource-table:not(.resource-table-nested) td:nth-child(3) {
|
||||
.md-typeset .resource-table:not(.resource-table-nested) th:nth-child(3),
|
||||
.md-typeset .resource-table:not(.resource-table-nested) td:nth-child(3) {
|
||||
width: 5%;
|
||||
white-space: nowrap;
|
||||
font-size: 0.63rem;
|
||||
}
|
||||
|
||||
.resource-table:not(.resource-table-nested) th:nth-last-child(2),
|
||||
.resource-table:not(.resource-table-nested) td:nth-last-child(2) {
|
||||
width: 45%;
|
||||
.md-typeset .resource-table:not(.resource-table-nested) th:nth-last-child(2),
|
||||
.md-typeset .resource-table:not(.resource-table-nested) td:nth-last-child(2) {
|
||||
white-space: normal;
|
||||
overflow-wrap: anywhere;
|
||||
font-size: 0.63rem;
|
||||
color: #777;
|
||||
}
|
||||
|
||||
.resource-table:not(.resource-table-nested) th:nth-last-child(1),
|
||||
.resource-table:not(.resource-table-nested) td:nth-last-child(1) {
|
||||
width: 30%;
|
||||
white-space: normal;
|
||||
overflow-wrap: anywhere;
|
||||
word-break: break-all;
|
||||
font-size: 0.72rem;
|
||||
.md-typeset .resource-table:not(.resource-table-nested) td:nth-last-child(2) {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* ---- NESTED TABLE: Code(16%) Type(5%) Req(4%) Def(6%) Descr(36%) Constr(31%) ---- */
|
||||
.resource-table-nested {
|
||||
.md-typeset .resource-table:not(.resource-table-nested) th:nth-last-child(1),
|
||||
.md-typeset .resource-table:not(.resource-table-nested) td:nth-last-child(1) {
|
||||
width: 20%;
|
||||
white-space: normal;
|
||||
overflow-wrap: anywhere;
|
||||
font-family: ui-monospace, "Cascadia Code", "Fira Code", monospace;
|
||||
font-size: 0.62rem;
|
||||
}
|
||||
|
||||
/* ---- NESTED TABLE ---- */
|
||||
.md-typeset .resource-table-nested {
|
||||
width: 100%;
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
.resource-table-nested th,
|
||||
.resource-table-nested td {
|
||||
.md-typeset .resource-table-nested th,
|
||||
.md-typeset .resource-table-nested td {
|
||||
white-space: normal;
|
||||
overflow-wrap: anywhere;
|
||||
word-break: break-word;
|
||||
font-size: 0.72rem;
|
||||
padding: 0.25rem 0.3rem;
|
||||
}
|
||||
|
||||
.resource-table-nested th:nth-child(2),
|
||||
.resource-table-nested td:nth-child(2) {
|
||||
width: 16%;
|
||||
.md-typeset .resource-table-nested th:nth-child(2),
|
||||
.md-typeset .resource-table-nested td:nth-child(2) {
|
||||
width: 19%;
|
||||
min-width: 16ch;
|
||||
}
|
||||
|
||||
.resource-table-nested td:nth-child(2) code {
|
||||
.md-typeset .resource-table-nested td:nth-child(2) code {
|
||||
font-weight: 700;
|
||||
font-size: 0.72rem;
|
||||
}
|
||||
|
||||
.resource-table-nested th:nth-child(3),
|
||||
.resource-table-nested td:nth-child(3) {
|
||||
width: 5%;
|
||||
white-space: nowrap;
|
||||
font-size: 0.63rem;
|
||||
}
|
||||
|
||||
/* Required column: green ✓ instead of text "yes" */
|
||||
.resource-table-nested th:nth-child(4),
|
||||
.resource-table-nested td:nth-child(4) {
|
||||
width: 5%;
|
||||
.md-typeset .resource-table-nested th:nth-child(4),
|
||||
.md-typeset .resource-table-nested td:nth-child(4) {
|
||||
width: 3%;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.resource-table-nested td:nth-child(4) strong {
|
||||
display: none;
|
||||
.md-typeset .resource-table-nested td:nth-child(4):not(:empty) {
|
||||
font-size: 0;
|
||||
}
|
||||
|
||||
.resource-table-nested td:nth-child(4):has(strong)::before {
|
||||
content: "✓";
|
||||
color: #27ae60;
|
||||
.md-typeset .resource-table-nested td:nth-child(4):not(:empty)::before {
|
||||
content: "★";
|
||||
color: #e74c3c;
|
||||
font-weight: 700;
|
||||
font-size: 0.9rem;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.resource-table-nested th:nth-child(5),
|
||||
.resource-table-nested td:nth-child(5) {
|
||||
.md-typeset .resource-table-nested th:nth-child(3),
|
||||
.md-typeset .resource-table-nested td:nth-child(3) {
|
||||
width: 5%;
|
||||
white-space: nowrap;
|
||||
font-size: 0.63rem;
|
||||
}
|
||||
|
||||
.md-typeset .resource-table-nested th:nth-child(5),
|
||||
.md-typeset .resource-table-nested td:nth-child(5) {
|
||||
width: 6%;
|
||||
white-space: nowrap;
|
||||
color: #2c6f8c;
|
||||
font-size: 0.72rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.resource-table-nested th:nth-child(6),
|
||||
.resource-table-nested td:nth-child(6) {
|
||||
width: 35%;
|
||||
.md-typeset .resource-table-nested th:nth-child(6),
|
||||
.md-typeset .resource-table-nested td:nth-child(6) {
|
||||
width: 37%;
|
||||
font-size: 0.63rem;
|
||||
color: #777;
|
||||
word-break: break-word;
|
||||
}
|
||||
.md-typeset .resource-table-nested td:nth-child(6) {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.resource-table-nested th:nth-child(7),
|
||||
.resource-table-nested td:nth-child(7) {
|
||||
width: 31%;
|
||||
word-break: break-all;
|
||||
.md-typeset .resource-table-nested th:nth-child(7),
|
||||
.md-typeset .resource-table-nested td:nth-child(7) {
|
||||
width: 30%;
|
||||
font-family: ui-monospace, "Cascadia Code", "Fira Code", monospace;
|
||||
font-size: 0.62rem;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.resource-table th:nth-child(7),
|
||||
@@ -512,3 +547,4 @@ body[data-md-url*="_instruction"] .md-typeset h3 {
|
||||
text-align: left;
|
||||
white-space: normal;
|
||||
}
|
||||
/* v20260718-1015 */
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
# План редизайна таблиц документации (Этап 1 — CSS)
|
||||
|
||||
> На основе рекомендаций Соннета. Только CSS, без правок генератора.
|
||||
|
||||
## Что делаем
|
||||
|
||||
| # | Изменение | CSS |
|
||||
|---|---|---|
|
||||
| 1 | Убрать ID | `display: none` на `th:nth-child(1)`, `td:nth-child(1)` |
|
||||
| 2 | ★ вместо колонки Required | Скрыть `td:nth-child(4)` в nested, `::before` на Code для required строк |
|
||||
| 3 | Monospace для Constraints | `font-family: monospace`, `overflow-wrap: anywhere` |
|
||||
| 4 | Sticky thead | `position: sticky; top: 0` |
|
||||
| 5 | line-clamp(2) Description | `-webkit-line-clamp: 2`, `overflow: hidden` |
|
||||
| 6 | Zebra striping | `tr:nth-child(even) { background: #fafafa }` |
|
||||
| 7 | Новые ширины колонок | Пересчёт после удаления ID и Required |
|
||||
|
||||
## Новые ширины
|
||||
|
||||
**Основная таблица (4 колонки, без ID):**
|
||||
Code(22%) | Type(6%) | Description(42%) | Constraints(30%)
|
||||
|
||||
**Основная с Default (5 колонок):**
|
||||
Code(22%) | Type(5%) | Default(10%) | Description(33%) | Constraints(30%)
|
||||
|
||||
**Nested (5 колонок, без ID и Required):**
|
||||
★Code(22%) | Type(5%) | Default(10%) | Description(33%) | Constraints(30%)
|
||||
|
||||
## Порядок действий
|
||||
|
||||
1. Обновить `extra.css`
|
||||
2. Скопировать в `generated/test/docs/30_registry/assets/`
|
||||
3. Пересобрать `site_test` через Docker
|
||||
4. Перезапустить HTTP-сервер
|
||||
5. Проверить в браузере
|
||||
6. Закоммитить через ВМ
|
||||
@@ -0,0 +1,96 @@
|
||||
# Шаблон страницы ресурса (документация)
|
||||
|
||||
> Актуально на 2026-07-18. Применять ко всем сервисам.
|
||||
|
||||
## Структура страницы
|
||||
|
||||
```markdown
|
||||
# Resource nubes_SERVICE · Service ID: N · Service Name: DISPLAY_NAME
|
||||
|
||||
**Manual** · [Create params](SERVICE_params_create.md) · [Modify params](SERVICE_params_modify.md) · [Output params](SERVICE_outputs.md) · [Operations](SERVICE_ops.md) · [Example](SERVICE_example.md)
|
||||
```
|
||||
|
||||
**Правила:**
|
||||
- Заголовок — ОДНА строка, разделители `·`
|
||||
- Табы — активная вкладка `**жирным**`, разделители `·`
|
||||
- SERVICE = имя ресурса из YAML (`spec.Name`), DISPLAY_NAME = `spec.ServiceDisplayName`
|
||||
|
||||
## MAN
|
||||
|
||||
```markdown
|
||||
## MAN
|
||||
|
||||
<div class="man-content" markdown="1">
|
||||
|
||||
# Инструкция ...
|
||||
|
||||
...
|
||||
|
||||
</div>
|
||||
```
|
||||
|
||||
- Весь MAN-контент внутри `<div class="man-content" markdown="1">`
|
||||
- Шрифт: 0.62rem (CSS: `.md-typeset .man-content`)
|
||||
- Требует `md_in_html` в `mkdocs.yml`
|
||||
|
||||
## Таблицы параметров
|
||||
|
||||
### Основная (Create/Modify params)
|
||||
|
||||
5 колонок (ID скрыт): Code | Type | (Default) | Description | Constraints
|
||||
|
||||
```html
|
||||
<table class="resource-table resource-table-compact resource-table-required">
|
||||
<thead><tr><th>ID</th><th>Code</th><th>Type</th><th>Description</th><th>Constraints</th></tr></thead>
|
||||
```
|
||||
|
||||
### Nested (map-fixed/array-map-fixed)
|
||||
|
||||
7 колонок: ID | Code | Type | Required | Default | Description | Constraints
|
||||
ID скрыт, Required — ★ для непустых ячеек.
|
||||
|
||||
```html
|
||||
<table class="resource-table resource-table-compact resource-table-nested">
|
||||
<thead><tr><th>ID</th><th>Code</th><th>Type</th><th>Required</th><th>Default</th><th>Description</th><th>Constraints</th></tr></thead>
|
||||
```
|
||||
|
||||
## CSS (глобальный, `docs/30_registry/assets/extra.css`)
|
||||
|
||||
| Элемент | Правило |
|
||||
|---|---|
|
||||
| ID колонка | `display: none` |
|
||||
| Required | `td:not(:empty)::before { content: "★"; color: #e74c3c; }` |
|
||||
| Code | 25% (main), 19% (nested), жирный |
|
||||
| Type | 5%, 0.63rem |
|
||||
| Default | 6% (nested), синий `#2c6f8c` |
|
||||
| Description | line-clamp(2) на `td`, мелкий серый |
|
||||
| Constraints | monospace 0.62rem, `word-break: break-word` |
|
||||
| thead | sticky, nowrap, 0.72rem |
|
||||
| tbody | zebra `tr:nth-child(even) { #fafafa }` |
|
||||
| MAN | `.man-content { font-size: 0.62rem; }` |
|
||||
| Заголовок h1 | 0.77rem |
|
||||
| Табы p | 0.65rem |
|
||||
| **Важно** | Все селекторы с префиксом `.md-typeset` |
|
||||
|
||||
## mkdocs.yml
|
||||
|
||||
Добавить в `markdown_extensions`:
|
||||
```yaml
|
||||
markdown_extensions:
|
||||
- md_in_html
|
||||
```
|
||||
|
||||
## Генератор (`TOOLS/docs-generator/internal/writers/writers.go`)
|
||||
|
||||
Функции для правки:
|
||||
- `buildHeader()` — заголовок + табы (одна строка, `·`, активная жирным)
|
||||
- `buildManualPage()` — MAN в `<div class="man-content" markdown="1">`
|
||||
- `renderParamTable()` — классы таблиц
|
||||
- `renderModifyTable()` — модифай без лишних колонок если пустые
|
||||
|
||||
## Порядок генерации
|
||||
|
||||
1. Правим `writers.go`
|
||||
2. `cd TOOLS/docs-generator && go build -o ../bin/docs-generator .`
|
||||
3. `./02_generate_resources_and_docs_v2.sh --profile TOOLS/config/test`
|
||||
4. `mkdocs build` или `./04_build_and_publish_docs.sh`
|
||||
@@ -36,6 +36,7 @@ extra_javascript:
|
||||
- 30_registry/javascripts/fix-slash.js
|
||||
|
||||
markdown_extensions:
|
||||
- md_in_html
|
||||
- admonition
|
||||
- attr_list
|
||||
- toc:
|
||||
|
||||
Reference in New Issue
Block a user