mkdocs-dbml-plugin 1.0.0__tar.gz
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.
- mkdocs_dbml_plugin-1.0.0/LICENSE +21 -0
- mkdocs_dbml_plugin-1.0.0/MANIFEST.in +10 -0
- mkdocs_dbml_plugin-1.0.0/PKG-INFO +272 -0
- mkdocs_dbml_plugin-1.0.0/README.md +241 -0
- mkdocs_dbml_plugin-1.0.0/mkdocs_dbml_plugin/__init__.py +4 -0
- mkdocs_dbml_plugin-1.0.0/mkdocs_dbml_plugin/_routing.pyx +136 -0
- mkdocs_dbml_plugin-1.0.0/mkdocs_dbml_plugin/_routing_py.py +250 -0
- mkdocs_dbml_plugin-1.0.0/mkdocs_dbml_plugin/config.py +55 -0
- mkdocs_dbml_plugin-1.0.0/mkdocs_dbml_plugin/layout.py +88 -0
- mkdocs_dbml_plugin-1.0.0/mkdocs_dbml_plugin/plugin.py +440 -0
- mkdocs_dbml_plugin-1.0.0/mkdocs_dbml_plugin/renderer.py +788 -0
- mkdocs_dbml_plugin-1.0.0/mkdocs_dbml_plugin/routing.py +10 -0
- mkdocs_dbml_plugin-1.0.0/mkdocs_dbml_plugin.egg-info/PKG-INFO +272 -0
- mkdocs_dbml_plugin-1.0.0/mkdocs_dbml_plugin.egg-info/SOURCES.txt +19 -0
- mkdocs_dbml_plugin-1.0.0/mkdocs_dbml_plugin.egg-info/dependency_links.txt +1 -0
- mkdocs_dbml_plugin-1.0.0/mkdocs_dbml_plugin.egg-info/entry_points.txt +2 -0
- mkdocs_dbml_plugin-1.0.0/mkdocs_dbml_plugin.egg-info/requires.txt +6 -0
- mkdocs_dbml_plugin-1.0.0/mkdocs_dbml_plugin.egg-info/top_level.txt +1 -0
- mkdocs_dbml_plugin-1.0.0/pyproject.toml +50 -0
- mkdocs_dbml_plugin-1.0.0/setup.cfg +4 -0
- mkdocs_dbml_plugin-1.0.0/setup.py +17 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ZhuchkaTriplesix
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mkdocs-dbml-plugin
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: MkDocs plugin to render DBML as interactive ERD diagrams
|
|
5
|
+
Author-email: ZhuchkaTriplesix <mrlololoshka94@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/ZhuchkaTriplesix/mkdocs-dbml
|
|
8
|
+
Project-URL: Documentation, https://github.com/ZhuchkaTriplesix/mkdocs-dbml#readme
|
|
9
|
+
Project-URL: Repository, https://github.com/ZhuchkaTriplesix/mkdocs-dbml
|
|
10
|
+
Project-URL: Issues, https://github.com/ZhuchkaTriplesix/mkdocs-dbml/issues
|
|
11
|
+
Keywords: mkdocs,plugin,dbml,erd,diagram,documentation
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Topic :: Documentation
|
|
15
|
+
Classifier: Topic :: Text Processing :: Markup
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Requires-Python: >=3.9
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: mkdocs>=1.0.0
|
|
26
|
+
Requires-Dist: numpy>=1.20.0
|
|
27
|
+
Requires-Dist: pydbml>=1.0.0
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: cython>=0.29; extra == "dev"
|
|
30
|
+
Dynamic: license-file
|
|
31
|
+
|
|
32
|
+
# MkDocs DBML Plugin
|
|
33
|
+
|
|
34
|
+
MkDocs plugin that renders [DBML](https://dbml.dbdiagram.io/) code blocks as interactive, visual ERD (Entity-Relationship Diagram) directly in your documentation.
|
|
35
|
+
|
|
36
|
+
## Features
|
|
37
|
+
|
|
38
|
+
- **Interactive SVG diagrams** — drag tables, zoom with mouse wheel, pan the canvas
|
|
39
|
+
- **Field-to-field connections** — relationship lines go from the exact FK field to the exact PK field
|
|
40
|
+
- **Orthogonal routing** — lines use right-angle paths and automatically avoid overlapping tables
|
|
41
|
+
- **Click-to-select** — click any relationship line to highlight it and its connected fields
|
|
42
|
+
- **Crow's foot notation** — classic ERD markers for one-to-one, one-to-many, many-to-many
|
|
43
|
+
- **Material Design 3 icons** — PK, FK, NOT NULL, UNIQUE badges on fields
|
|
44
|
+
- **7 color themes** — default, ocean, sunset, forest, dark, dark_gray, black
|
|
45
|
+
- **High performance** — optional Cython-compiled routing engine; Numba JIT fallback
|
|
46
|
+
|
|
47
|
+
## Installation
|
|
48
|
+
|
|
49
|
+
### From source (local project)
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
git clone https://github.com/ZhuchkaTriplesix/mkdocs-dbml.git
|
|
53
|
+
cd mkdocs-dbml
|
|
54
|
+
pip install -e .
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### From source with Cython (optional, for best performance)
|
|
58
|
+
|
|
59
|
+
If you have a C compiler available (MSVC on Windows, gcc/clang on Linux/macOS):
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
pip install cython
|
|
63
|
+
python setup.py build_ext --inplace
|
|
64
|
+
pip install -e .
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Without Cython the plugin works fine — it falls back to a pure-Python router.
|
|
68
|
+
|
|
69
|
+
### Dependencies
|
|
70
|
+
|
|
71
|
+
Installed automatically by `pip install`:
|
|
72
|
+
|
|
73
|
+
| Package | Purpose |
|
|
74
|
+
|---------|---------|
|
|
75
|
+
| `mkdocs >= 1.0` | Documentation framework |
|
|
76
|
+
| `pydbml >= 1.0` | DBML parser |
|
|
77
|
+
|
|
78
|
+
## Quick start
|
|
79
|
+
|
|
80
|
+
### 1. Enable the plugin in `mkdocs.yml`
|
|
81
|
+
|
|
82
|
+
```yaml
|
|
83
|
+
plugins:
|
|
84
|
+
- search
|
|
85
|
+
- dbml
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### 2. Write DBML in any Markdown file
|
|
89
|
+
|
|
90
|
+
````markdown
|
|
91
|
+
```dbml
|
|
92
|
+
Table users {
|
|
93
|
+
id integer [primary key]
|
|
94
|
+
username varchar(50) [not null, unique]
|
|
95
|
+
email varchar(100) [not null]
|
|
96
|
+
created_at timestamp
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
Table posts {
|
|
100
|
+
id integer [primary key]
|
|
101
|
+
user_id integer [ref: > users.id]
|
|
102
|
+
title varchar(200) [not null]
|
|
103
|
+
content text
|
|
104
|
+
published boolean [default: false]
|
|
105
|
+
created_at timestamp
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
Table comments {
|
|
109
|
+
id integer [primary key]
|
|
110
|
+
post_id integer [ref: > posts.id]
|
|
111
|
+
user_id integer [ref: > users.id]
|
|
112
|
+
content text [not null]
|
|
113
|
+
created_at timestamp
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
````
|
|
117
|
+
|
|
118
|
+
### 3. Build or serve
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
mkdocs serve # live preview at http://127.0.0.1:8000
|
|
122
|
+
mkdocs build # static output in site/
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
The plugin converts every `` ```dbml `` code block into an interactive SVG diagram.
|
|
126
|
+
|
|
127
|
+
### Including native `.dbml` files
|
|
128
|
+
|
|
129
|
+
You can embed the contents of a `.dbml` file instead of pasting DBML inline. Paths are relative to your `docs_dir`.
|
|
130
|
+
|
|
131
|
+
**Option 1 — single line with path (must end with `.dbml`, no spaces):**
|
|
132
|
+
|
|
133
|
+
````markdown
|
|
134
|
+
```dbml
|
|
135
|
+
schema.dbml
|
|
136
|
+
```
|
|
137
|
+
````
|
|
138
|
+
|
|
139
|
+
**Option 2 — explicit `file:` or `include:` prefix:**
|
|
140
|
+
|
|
141
|
+
````markdown
|
|
142
|
+
```dbml
|
|
143
|
+
file: schemas/public.dbml
|
|
144
|
+
```
|
|
145
|
+
````
|
|
146
|
+
|
|
147
|
+
The file is read from `docs_dir` (e.g. `docs/schema.dbml` or `docs/schemas/public.dbml`). Path traversal (`../`) outside `docs_dir` is not allowed.
|
|
148
|
+
|
|
149
|
+
## Configuration
|
|
150
|
+
|
|
151
|
+
All options are set under the `dbml` plugin entry in `mkdocs.yml`:
|
|
152
|
+
|
|
153
|
+
```yaml
|
|
154
|
+
plugins:
|
|
155
|
+
- dbml:
|
|
156
|
+
theme: default # color theme (see below)
|
|
157
|
+
show_indexes: true # display index information
|
|
158
|
+
show_notes: true # display table notes
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Themes
|
|
162
|
+
|
|
163
|
+
| Theme | Header gradient | Best for |
|
|
164
|
+
|-------|----------------|----------|
|
|
165
|
+
| `default` | Purple | Light backgrounds |
|
|
166
|
+
| `ocean` | Deep blue → cyan | Light backgrounds |
|
|
167
|
+
| `sunset` | Pink → blue | Light backgrounds |
|
|
168
|
+
| `forest` | Dark teal → green | Light backgrounds |
|
|
169
|
+
| `dark` | Dark violet | Dark backgrounds |
|
|
170
|
+
| `dark_gray` | Gray → slate | Dark backgrounds, neutral |
|
|
171
|
+
| `black` | Near-black → gray | Dark backgrounds, high contrast |
|
|
172
|
+
|
|
173
|
+
Example with the dark theme:
|
|
174
|
+
|
|
175
|
+
```yaml
|
|
176
|
+
plugins:
|
|
177
|
+
- dbml:
|
|
178
|
+
theme: dark
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## DBML syntax cheat-sheet
|
|
182
|
+
|
|
183
|
+
```dbml
|
|
184
|
+
Table table_name {
|
|
185
|
+
column_name column_type [attributes]
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Column attributes
|
|
190
|
+
|
|
191
|
+
| Attribute | Syntax |
|
|
192
|
+
|-----------|--------|
|
|
193
|
+
| Primary key | `[primary key]` or `[pk]` |
|
|
194
|
+
| Not null | `[not null]` |
|
|
195
|
+
| Unique | `[unique]` |
|
|
196
|
+
| Default value | `[default: value]` |
|
|
197
|
+
| Foreign key | `[ref: > other_table.column]` |
|
|
198
|
+
|
|
199
|
+
### Relationship types
|
|
200
|
+
|
|
201
|
+
| Syntax | Meaning | Markers |
|
|
202
|
+
|--------|---------|---------|
|
|
203
|
+
| `ref: > table.col` | Many-to-one | Circle → Crow's foot |
|
|
204
|
+
| `ref: < table.col` | One-to-many | Crow's foot → Bar |
|
|
205
|
+
| `ref: - table.col` | One-to-one | Bar → Bar |
|
|
206
|
+
| `ref: <> table.col` | Many-to-many | Crow's foot → Crow's foot |
|
|
207
|
+
|
|
208
|
+
### Indexes and notes
|
|
209
|
+
|
|
210
|
+
```dbml
|
|
211
|
+
Table example {
|
|
212
|
+
id integer [pk]
|
|
213
|
+
user_id integer
|
|
214
|
+
post_id integer
|
|
215
|
+
|
|
216
|
+
indexes {
|
|
217
|
+
user_id
|
|
218
|
+
(user_id, post_id) [unique]
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
Note: 'Description of this table'
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Full DBML specification: [dbml.dbdiagram.io/docs](https://dbml.dbdiagram.io/docs/)
|
|
226
|
+
|
|
227
|
+
## Interaction guide
|
|
228
|
+
|
|
229
|
+
| Action | How |
|
|
230
|
+
|--------|-----|
|
|
231
|
+
| **Move a table** | Click and drag the table |
|
|
232
|
+
| **Pan the canvas** | Click and drag empty space |
|
|
233
|
+
| **Zoom** | Mouse wheel (10% – 300%) |
|
|
234
|
+
| **Fullscreen** | Click the expand button (top-right), Esc to exit |
|
|
235
|
+
| **Highlight connections** | Hover over a table |
|
|
236
|
+
| **Select a line** | Click on any relationship line |
|
|
237
|
+
| **Field tooltip** | Hover over a field row |
|
|
238
|
+
|
|
239
|
+
## Project structure
|
|
240
|
+
|
|
241
|
+
```
|
|
242
|
+
mkdocs-dbml/
|
|
243
|
+
├── setup.py # package config
|
|
244
|
+
├── requirements.txt
|
|
245
|
+
├── mkdocs_dbml_plugin/
|
|
246
|
+
│ ├── __init__.py
|
|
247
|
+
│ ├── plugin.py # MkDocs hook + interactive JS
|
|
248
|
+
│ ├── renderer.py # DBML → SVG rendering + CSS
|
|
249
|
+
│ ├── layout.py # BFS graph layout engine
|
|
250
|
+
│ ├── config.py # theme definitions
|
|
251
|
+
│ ├── routing.py # import wrapper (Cython → Python)
|
|
252
|
+
│ ├── _routing.pyx # Cython routing (optional)
|
|
253
|
+
│ └── _routing_py.py # pure-Python routing fallback
|
|
254
|
+
└── example/ # demo MkDocs site
|
|
255
|
+
├── mkdocs.yml
|
|
256
|
+
└── docs/
|
|
257
|
+
└── *.md
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
## Publishing to PyPI (maintainers)
|
|
261
|
+
|
|
262
|
+
```bash
|
|
263
|
+
pip install build twine
|
|
264
|
+
python -m build
|
|
265
|
+
twine upload dist/*
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Use an API token from [pypi.org/manage/account](https://pypi.org/manage/account/) (env `TWINE_USERNAME=__token__`, `TWINE_PASSWORD=<token>`).
|
|
269
|
+
|
|
270
|
+
## License
|
|
271
|
+
|
|
272
|
+
MIT
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# MkDocs DBML Plugin
|
|
2
|
+
|
|
3
|
+
MkDocs plugin that renders [DBML](https://dbml.dbdiagram.io/) code blocks as interactive, visual ERD (Entity-Relationship Diagram) directly in your documentation.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Interactive SVG diagrams** — drag tables, zoom with mouse wheel, pan the canvas
|
|
8
|
+
- **Field-to-field connections** — relationship lines go from the exact FK field to the exact PK field
|
|
9
|
+
- **Orthogonal routing** — lines use right-angle paths and automatically avoid overlapping tables
|
|
10
|
+
- **Click-to-select** — click any relationship line to highlight it and its connected fields
|
|
11
|
+
- **Crow's foot notation** — classic ERD markers for one-to-one, one-to-many, many-to-many
|
|
12
|
+
- **Material Design 3 icons** — PK, FK, NOT NULL, UNIQUE badges on fields
|
|
13
|
+
- **7 color themes** — default, ocean, sunset, forest, dark, dark_gray, black
|
|
14
|
+
- **High performance** — optional Cython-compiled routing engine; Numba JIT fallback
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
### From source (local project)
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
git clone https://github.com/ZhuchkaTriplesix/mkdocs-dbml.git
|
|
22
|
+
cd mkdocs-dbml
|
|
23
|
+
pip install -e .
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### From source with Cython (optional, for best performance)
|
|
27
|
+
|
|
28
|
+
If you have a C compiler available (MSVC on Windows, gcc/clang on Linux/macOS):
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pip install cython
|
|
32
|
+
python setup.py build_ext --inplace
|
|
33
|
+
pip install -e .
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Without Cython the plugin works fine — it falls back to a pure-Python router.
|
|
37
|
+
|
|
38
|
+
### Dependencies
|
|
39
|
+
|
|
40
|
+
Installed automatically by `pip install`:
|
|
41
|
+
|
|
42
|
+
| Package | Purpose |
|
|
43
|
+
|---------|---------|
|
|
44
|
+
| `mkdocs >= 1.0` | Documentation framework |
|
|
45
|
+
| `pydbml >= 1.0` | DBML parser |
|
|
46
|
+
|
|
47
|
+
## Quick start
|
|
48
|
+
|
|
49
|
+
### 1. Enable the plugin in `mkdocs.yml`
|
|
50
|
+
|
|
51
|
+
```yaml
|
|
52
|
+
plugins:
|
|
53
|
+
- search
|
|
54
|
+
- dbml
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### 2. Write DBML in any Markdown file
|
|
58
|
+
|
|
59
|
+
````markdown
|
|
60
|
+
```dbml
|
|
61
|
+
Table users {
|
|
62
|
+
id integer [primary key]
|
|
63
|
+
username varchar(50) [not null, unique]
|
|
64
|
+
email varchar(100) [not null]
|
|
65
|
+
created_at timestamp
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
Table posts {
|
|
69
|
+
id integer [primary key]
|
|
70
|
+
user_id integer [ref: > users.id]
|
|
71
|
+
title varchar(200) [not null]
|
|
72
|
+
content text
|
|
73
|
+
published boolean [default: false]
|
|
74
|
+
created_at timestamp
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
Table comments {
|
|
78
|
+
id integer [primary key]
|
|
79
|
+
post_id integer [ref: > posts.id]
|
|
80
|
+
user_id integer [ref: > users.id]
|
|
81
|
+
content text [not null]
|
|
82
|
+
created_at timestamp
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
````
|
|
86
|
+
|
|
87
|
+
### 3. Build or serve
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
mkdocs serve # live preview at http://127.0.0.1:8000
|
|
91
|
+
mkdocs build # static output in site/
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The plugin converts every `` ```dbml `` code block into an interactive SVG diagram.
|
|
95
|
+
|
|
96
|
+
### Including native `.dbml` files
|
|
97
|
+
|
|
98
|
+
You can embed the contents of a `.dbml` file instead of pasting DBML inline. Paths are relative to your `docs_dir`.
|
|
99
|
+
|
|
100
|
+
**Option 1 — single line with path (must end with `.dbml`, no spaces):**
|
|
101
|
+
|
|
102
|
+
````markdown
|
|
103
|
+
```dbml
|
|
104
|
+
schema.dbml
|
|
105
|
+
```
|
|
106
|
+
````
|
|
107
|
+
|
|
108
|
+
**Option 2 — explicit `file:` or `include:` prefix:**
|
|
109
|
+
|
|
110
|
+
````markdown
|
|
111
|
+
```dbml
|
|
112
|
+
file: schemas/public.dbml
|
|
113
|
+
```
|
|
114
|
+
````
|
|
115
|
+
|
|
116
|
+
The file is read from `docs_dir` (e.g. `docs/schema.dbml` or `docs/schemas/public.dbml`). Path traversal (`../`) outside `docs_dir` is not allowed.
|
|
117
|
+
|
|
118
|
+
## Configuration
|
|
119
|
+
|
|
120
|
+
All options are set under the `dbml` plugin entry in `mkdocs.yml`:
|
|
121
|
+
|
|
122
|
+
```yaml
|
|
123
|
+
plugins:
|
|
124
|
+
- dbml:
|
|
125
|
+
theme: default # color theme (see below)
|
|
126
|
+
show_indexes: true # display index information
|
|
127
|
+
show_notes: true # display table notes
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Themes
|
|
131
|
+
|
|
132
|
+
| Theme | Header gradient | Best for |
|
|
133
|
+
|-------|----------------|----------|
|
|
134
|
+
| `default` | Purple | Light backgrounds |
|
|
135
|
+
| `ocean` | Deep blue → cyan | Light backgrounds |
|
|
136
|
+
| `sunset` | Pink → blue | Light backgrounds |
|
|
137
|
+
| `forest` | Dark teal → green | Light backgrounds |
|
|
138
|
+
| `dark` | Dark violet | Dark backgrounds |
|
|
139
|
+
| `dark_gray` | Gray → slate | Dark backgrounds, neutral |
|
|
140
|
+
| `black` | Near-black → gray | Dark backgrounds, high contrast |
|
|
141
|
+
|
|
142
|
+
Example with the dark theme:
|
|
143
|
+
|
|
144
|
+
```yaml
|
|
145
|
+
plugins:
|
|
146
|
+
- dbml:
|
|
147
|
+
theme: dark
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## DBML syntax cheat-sheet
|
|
151
|
+
|
|
152
|
+
```dbml
|
|
153
|
+
Table table_name {
|
|
154
|
+
column_name column_type [attributes]
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Column attributes
|
|
159
|
+
|
|
160
|
+
| Attribute | Syntax |
|
|
161
|
+
|-----------|--------|
|
|
162
|
+
| Primary key | `[primary key]` or `[pk]` |
|
|
163
|
+
| Not null | `[not null]` |
|
|
164
|
+
| Unique | `[unique]` |
|
|
165
|
+
| Default value | `[default: value]` |
|
|
166
|
+
| Foreign key | `[ref: > other_table.column]` |
|
|
167
|
+
|
|
168
|
+
### Relationship types
|
|
169
|
+
|
|
170
|
+
| Syntax | Meaning | Markers |
|
|
171
|
+
|--------|---------|---------|
|
|
172
|
+
| `ref: > table.col` | Many-to-one | Circle → Crow's foot |
|
|
173
|
+
| `ref: < table.col` | One-to-many | Crow's foot → Bar |
|
|
174
|
+
| `ref: - table.col` | One-to-one | Bar → Bar |
|
|
175
|
+
| `ref: <> table.col` | Many-to-many | Crow's foot → Crow's foot |
|
|
176
|
+
|
|
177
|
+
### Indexes and notes
|
|
178
|
+
|
|
179
|
+
```dbml
|
|
180
|
+
Table example {
|
|
181
|
+
id integer [pk]
|
|
182
|
+
user_id integer
|
|
183
|
+
post_id integer
|
|
184
|
+
|
|
185
|
+
indexes {
|
|
186
|
+
user_id
|
|
187
|
+
(user_id, post_id) [unique]
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
Note: 'Description of this table'
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Full DBML specification: [dbml.dbdiagram.io/docs](https://dbml.dbdiagram.io/docs/)
|
|
195
|
+
|
|
196
|
+
## Interaction guide
|
|
197
|
+
|
|
198
|
+
| Action | How |
|
|
199
|
+
|--------|-----|
|
|
200
|
+
| **Move a table** | Click and drag the table |
|
|
201
|
+
| **Pan the canvas** | Click and drag empty space |
|
|
202
|
+
| **Zoom** | Mouse wheel (10% – 300%) |
|
|
203
|
+
| **Fullscreen** | Click the expand button (top-right), Esc to exit |
|
|
204
|
+
| **Highlight connections** | Hover over a table |
|
|
205
|
+
| **Select a line** | Click on any relationship line |
|
|
206
|
+
| **Field tooltip** | Hover over a field row |
|
|
207
|
+
|
|
208
|
+
## Project structure
|
|
209
|
+
|
|
210
|
+
```
|
|
211
|
+
mkdocs-dbml/
|
|
212
|
+
├── setup.py # package config
|
|
213
|
+
├── requirements.txt
|
|
214
|
+
├── mkdocs_dbml_plugin/
|
|
215
|
+
│ ├── __init__.py
|
|
216
|
+
│ ├── plugin.py # MkDocs hook + interactive JS
|
|
217
|
+
│ ├── renderer.py # DBML → SVG rendering + CSS
|
|
218
|
+
│ ├── layout.py # BFS graph layout engine
|
|
219
|
+
│ ├── config.py # theme definitions
|
|
220
|
+
│ ├── routing.py # import wrapper (Cython → Python)
|
|
221
|
+
│ ├── _routing.pyx # Cython routing (optional)
|
|
222
|
+
│ └── _routing_py.py # pure-Python routing fallback
|
|
223
|
+
└── example/ # demo MkDocs site
|
|
224
|
+
├── mkdocs.yml
|
|
225
|
+
└── docs/
|
|
226
|
+
└── *.md
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## Publishing to PyPI (maintainers)
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
pip install build twine
|
|
233
|
+
python -m build
|
|
234
|
+
twine upload dist/*
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Use an API token from [pypi.org/manage/account](https://pypi.org/manage/account/) (env `TWINE_USERNAME=__token__`, `TWINE_PASSWORD=<token>`).
|
|
238
|
+
|
|
239
|
+
## License
|
|
240
|
+
|
|
241
|
+
MIT
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# cython: boundscheck=False, wraparound=False, cdivision=True
|
|
2
|
+
from libc.math cimport fabs
|
|
3
|
+
from libc.stdlib cimport malloc, free
|
|
4
|
+
|
|
5
|
+
cdef struct Rect:
|
|
6
|
+
double x, y, w, h
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
cdef int _overlaps_v(double vx, double y_lo, double y_hi,
|
|
10
|
+
Rect *rects, int n, int skip1, int skip2) noexcept nogil:
|
|
11
|
+
cdef int i
|
|
12
|
+
cdef Rect r
|
|
13
|
+
cdef double pad = 5.0
|
|
14
|
+
for i in range(n):
|
|
15
|
+
if i == skip1 or i == skip2:
|
|
16
|
+
continue
|
|
17
|
+
r = rects[i]
|
|
18
|
+
if r.x - pad <= vx <= r.x + r.w + pad:
|
|
19
|
+
if not (y_hi < r.y - pad or y_lo > r.y + r.h + pad):
|
|
20
|
+
return i
|
|
21
|
+
return -1
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
cdef double _path_cost(list waypoints):
|
|
25
|
+
cdef double cost = 0.0
|
|
26
|
+
cdef int i
|
|
27
|
+
cdef double x1, y1, x2, y2
|
|
28
|
+
for i in range(len(waypoints) - 1):
|
|
29
|
+
x1, y1 = waypoints[i]
|
|
30
|
+
x2, y2 = waypoints[i + 1]
|
|
31
|
+
cost += fabs(x2 - x1) + fabs(y2 - y1)
|
|
32
|
+
return cost
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
cdef list _route_one(double sx, double sy, double ex, double ey,
|
|
36
|
+
int skip1, int skip2, Rect *rects, int n, double gap):
|
|
37
|
+
cdef double mid_x = (sx + ex) / 2.0
|
|
38
|
+
cdef double y_lo = sy if sy < ey else ey
|
|
39
|
+
cdef double y_hi = sy if sy > ey else ey
|
|
40
|
+
cdef int blocker, dummy
|
|
41
|
+
cdef double left_x, right_x, jog_y, safe_x, stub
|
|
42
|
+
cdef bint left_ok, right_ok
|
|
43
|
+
|
|
44
|
+
blocker = _overlaps_v(mid_x, y_lo, y_hi, rects, n, skip1, skip2)
|
|
45
|
+
if blocker < 0:
|
|
46
|
+
return [(sx, sy), (mid_x, sy), (mid_x, ey), (ex, ey)]
|
|
47
|
+
|
|
48
|
+
left_x = rects[blocker].x - gap
|
|
49
|
+
right_x = rects[blocker].x + rects[blocker].w + gap
|
|
50
|
+
|
|
51
|
+
left_ok = _overlaps_v(left_x, y_lo, y_hi, rects, n, skip1, skip2) < 0
|
|
52
|
+
right_ok = _overlaps_v(right_x, y_lo, y_hi, rects, n, skip1, skip2) < 0
|
|
53
|
+
|
|
54
|
+
if left_ok and right_ok:
|
|
55
|
+
mid_x = left_x if fabs(left_x - sx) < fabs(right_x - sx) else right_x
|
|
56
|
+
elif left_ok:
|
|
57
|
+
mid_x = left_x
|
|
58
|
+
elif right_ok:
|
|
59
|
+
mid_x = right_x
|
|
60
|
+
else:
|
|
61
|
+
if sy < rects[blocker].y:
|
|
62
|
+
jog_y = rects[blocker].y - gap
|
|
63
|
+
else:
|
|
64
|
+
jog_y = rects[blocker].y + rects[blocker].h + gap
|
|
65
|
+
safe_x = left_x if fabs(left_x - sx) < fabs(right_x - sx) else right_x
|
|
66
|
+
stub = gap if ex < sx else -gap
|
|
67
|
+
return [
|
|
68
|
+
(sx, sy), (safe_x, sy), (safe_x, jog_y),
|
|
69
|
+
(ex + stub, jog_y), (ex + stub, ey), (ex, ey),
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
return [(sx, sy), (mid_x, sy), (mid_x, ey), (ex, ey)]
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def route_connection(from_rect, to_rect, field_y_from, field_y_to,
|
|
76
|
+
from_idx, to_idx, table_rects, gap=20.0):
|
|
77
|
+
cdef int n = len(table_rects)
|
|
78
|
+
cdef Rect *rects = <Rect *>malloc(n * sizeof(Rect))
|
|
79
|
+
if rects == NULL:
|
|
80
|
+
return [(0, 0), (0, 0)], 'right', 'left'
|
|
81
|
+
|
|
82
|
+
cdef int i
|
|
83
|
+
for i in range(n):
|
|
84
|
+
rects[i].x = table_rects[i][0]
|
|
85
|
+
rects[i].y = table_rects[i][1]
|
|
86
|
+
rects[i].w = table_rects[i][2]
|
|
87
|
+
rects[i].h = table_rects[i][3]
|
|
88
|
+
|
|
89
|
+
cdef double fx = from_rect[0], fy = from_rect[1], fw = from_rect[2], fh = from_rect[3]
|
|
90
|
+
cdef double tx = to_rect[0], ty = to_rect[1], tw = to_rect[2], th = to_rect[3]
|
|
91
|
+
cdef double sx, ex, cost, best_cost
|
|
92
|
+
cdef list wp, best_wp
|
|
93
|
+
cdef str best_sf, best_st
|
|
94
|
+
|
|
95
|
+
best_cost = 1e18
|
|
96
|
+
best_wp = []
|
|
97
|
+
best_sf = 'right'
|
|
98
|
+
best_st = 'left'
|
|
99
|
+
|
|
100
|
+
for sf in ('right', 'left'):
|
|
101
|
+
for st in ('right', 'left'):
|
|
102
|
+
sx = (fx + fw + 12.0) if sf == 'right' else (fx - 12.0)
|
|
103
|
+
ex = (tx - 12.0) if st == 'left' else (tx + tw + 12.0)
|
|
104
|
+
wp = _route_one(sx, field_y_from, ex, field_y_to,
|
|
105
|
+
from_idx, to_idx, rects, n, gap)
|
|
106
|
+
cost = _path_cost(wp)
|
|
107
|
+
|
|
108
|
+
for j in range(1, len(wp) - 1):
|
|
109
|
+
mx, my = wp[j]
|
|
110
|
+
for k in range(n):
|
|
111
|
+
if k == from_idx or k == to_idx:
|
|
112
|
+
continue
|
|
113
|
+
if rects[k].x <= mx <= rects[k].x + rects[k].w and rects[k].y <= my <= rects[k].y + rects[k].h:
|
|
114
|
+
cost += 100000
|
|
115
|
+
break
|
|
116
|
+
|
|
117
|
+
if cost < best_cost:
|
|
118
|
+
best_cost = cost
|
|
119
|
+
best_wp = wp
|
|
120
|
+
best_sf = sf
|
|
121
|
+
best_st = st
|
|
122
|
+
|
|
123
|
+
free(rects)
|
|
124
|
+
return best_wp, best_sf, best_st
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def build_table_rects(positions, dimensions):
|
|
128
|
+
names = sorted(positions.keys())
|
|
129
|
+
idx_map = {}
|
|
130
|
+
rects = []
|
|
131
|
+
for i, name in enumerate(names):
|
|
132
|
+
idx_map[name] = i
|
|
133
|
+
px, py = positions[name]
|
|
134
|
+
w, h = dimensions[name]
|
|
135
|
+
rects.append((px, py, w, h))
|
|
136
|
+
return names, idx_map, rects
|