feat: новый дизайн документации — шаблон, генератор, CSS, md_in_html, версия 5.1.2

This commit is contained in:
Naeel
2026-07-18 09:50:37 +03:00
parent 1276143973
commit ad3b986d89
6 changed files with 253 additions and 79 deletions
+1 -1
View File
@@ -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 {
+105 -69
View File
@@ -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 */
+35
View File
@@ -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. Закоммитить через ВМ
+96
View File
@@ -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`
+1
View File
@@ -36,6 +36,7 @@ extra_javascript:
- 30_registry/javascripts/fix-slash.js
markdown_extensions:
- md_in_html
- admonition
- attr_list
- toc: