labull-framework 0.1.4__tar.gz → 0.1.4.2__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.
- {labull_framework-0.1.4/labull_framework.egg-info → labull_framework-0.1.4.2}/PKG-INFO +1 -1
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework/canvas/data.py +34 -47
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework/canvas/static/canvas.css +100 -47
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework/canvas/static/canvas.js +519 -55
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework/canvas/static/page.html +3 -3
- {labull_framework-0.1.4 → labull_framework-0.1.4.2/labull_framework.egg-info}/PKG-INFO +1 -1
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/pyproject.toml +1 -1
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/LICENSE +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/MANIFEST.in +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/README-pypi.md +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework/__init__.py +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework/admin.py +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework/apps.py +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework/auth/__init__.py +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework/auth/backend.py +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework/auth/bootstrap.py +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework/auth/sso.py +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework/auth/views.py +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework/canvas/__init__.py +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework/canvas/gitinfo.py +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework/canvas/views.py +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework/env.py +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework/jsonio.py +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework/magic_block/__init__.py +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework/magic_block/deepcheck.py +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework/magic_block/devkit.py +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework/magic_block/dispatch.py +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework/magic_block/export.py +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework/magic_block/health.py +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework/magic_block/registry.py +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework/magic_block/sdk.py +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework/magic_block/service.py +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework/magic_block/validate.py +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework/magic_block/views.py +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework/management/__init__.py +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework/management/commands/__init__.py +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework/management/commands/labull_contract.py +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework/migrations/0001_initial.py +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework/migrations/__init__.py +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework/models.py +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework/settings.py +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework/urls.py +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework.egg-info/SOURCES.txt +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework.egg-info/dependency_links.txt +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework.egg-info/requires.txt +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework.egg-info/top_level.txt +0 -0
- {labull_framework-0.1.4 → labull_framework-0.1.4.2}/setup.cfg +0 -0
|
@@ -88,46 +88,6 @@ def _brief_line(obj: Any) -> str:
|
|
|
88
88
|
return brief.splitlines()[0].strip() if brief else ''
|
|
89
89
|
|
|
90
90
|
|
|
91
|
-
def _type_of(field: Any) -> str:
|
|
92
|
-
"""Django 字段 → **库里那一列的真实类型**(画布右侧那个小字)。
|
|
93
|
-
|
|
94
|
-
🔴 这里只回答"数据库里长什么样";"这个字段在 Django 里是什么"由 `_kind_of` 回答。
|
|
95
|
-
两者刻意分开:`FileField` 在库里就是一列 varchar,而人关心的是"这是个文件字段"。
|
|
96
|
-
"""
|
|
97
|
-
from django.db import models
|
|
98
|
-
|
|
99
|
-
mapping = (
|
|
100
|
-
(models.BigAutoField, 'bigint'),
|
|
101
|
-
(models.BigIntegerField, 'bigint'),
|
|
102
|
-
(models.AutoField, 'integer'),
|
|
103
|
-
(models.IntegerField, 'integer'),
|
|
104
|
-
(models.SmallIntegerField, 'integer'),
|
|
105
|
-
(models.PositiveIntegerField, 'integer'),
|
|
106
|
-
(models.BooleanField, 'boolean'),
|
|
107
|
-
(models.DateField, 'date'),
|
|
108
|
-
(models.DateTimeField, 'timestamp'),
|
|
109
|
-
(models.TimeField, 'time'),
|
|
110
|
-
(models.DurationField, 'interval'),
|
|
111
|
-
(models.DecimalField, 'numeric'),
|
|
112
|
-
(models.FloatField, 'real'),
|
|
113
|
-
(models.JSONField, 'jsonb'),
|
|
114
|
-
(models.UUIDField, 'uuid'),
|
|
115
|
-
(models.BinaryField, 'bytea'),
|
|
116
|
-
(models.FileField, 'varchar'),
|
|
117
|
-
(models.ImageField, 'varchar'),
|
|
118
|
-
(models.EmailField, 'varchar'),
|
|
119
|
-
(models.URLField, 'varchar'),
|
|
120
|
-
(models.SlugField, 'varchar'),
|
|
121
|
-
(models.GenericIPAddressField, 'inet'),
|
|
122
|
-
(models.CharField, 'varchar'),
|
|
123
|
-
(models.TextField, 'text'),
|
|
124
|
-
)
|
|
125
|
-
for cls, name in mapping:
|
|
126
|
-
if isinstance(field, cls):
|
|
127
|
-
return name
|
|
128
|
-
return 'text'
|
|
129
|
-
|
|
130
|
-
|
|
131
91
|
def _kind_of(field: Any) -> str:
|
|
132
92
|
"""Django 字段的**种类**(画布左侧那个彩色小标:枚举 / 文件 / 关联 / 金额 …)。
|
|
133
93
|
|
|
@@ -344,30 +304,57 @@ def shape() -> dict[str, list[dict[str, Any]]]:
|
|
|
344
304
|
|
|
345
305
|
|
|
346
306
|
def _type_of(field: Any) -> str:
|
|
347
|
-
"""Django 字段 →
|
|
307
|
+
"""Django 字段 → 契约里那几种类型之一(画布右侧那个小字:`varchar` / `text` / `bigint` …)。
|
|
308
|
+
|
|
309
|
+
🔴 这里只回答"**库里那一列**长什么样";"这个字段在 Django 里是什么"由 `_kind_of` 回答。
|
|
310
|
+
两者刻意分开:`FileField` 在库里就是一列 varchar ⇒ 这里回 `varchar`,
|
|
311
|
+
而画布左边那个彩色小标由 `kind` 说了算(`文件` / `图片`)。
|
|
312
|
+
|
|
313
|
+
⚠️ **顺序有意义**,写反了不报错、只是悄悄归错档:
|
|
314
|
+
· `DateTimeField` 是 `DateField` 的子类 ⇒ `created_at` 会报成 `date`(真踩过);
|
|
315
|
+
· `ImageField` 是 `FileField` 的子类、`EmailField` 是 `CharField` 的子类 ⇒ 具体的写在前面。
|
|
348
316
|
|
|
349
|
-
🔴
|
|
317
|
+
🔴 这个函数在本文件里**只能有一份**:曾经在下面又写了一份把这份整个遮掉,
|
|
318
|
+
于是 `FileField` 报成 `text`、`DateTimeField` 报成 `date` —— 而两份代码看着都"挺对"。
|
|
350
319
|
"""
|
|
351
320
|
from django.db import models
|
|
352
321
|
|
|
322
|
+
# 关联列:这张表里那一列的类型 = **对端主键**那一列的类型(`order_id` 是 bigint,不是 text)。
|
|
323
|
+
# ⚠️ 多对多在这一层没有自己的列(列在中间表上),而 `shape()` 也不会把 m2m 送到这里来。
|
|
324
|
+
target = getattr(field, 'target_field', None)
|
|
325
|
+
if target is not None and target is not field and not getattr(field, 'many_to_many', False):
|
|
326
|
+
return _type_of(target)
|
|
327
|
+
|
|
353
328
|
mapping = (
|
|
354
|
-
(models.BigAutoField, 'bigint'),
|
|
329
|
+
(models.BigAutoField, 'bigint'), # 子类链:BigAutoField ⊂ BigIntegerField ⊂ IntegerField
|
|
355
330
|
(models.BigIntegerField, 'bigint'),
|
|
331
|
+
(models.SmallIntegerField, 'integer'),
|
|
332
|
+
(models.PositiveIntegerField, 'integer'),
|
|
356
333
|
(models.AutoField, 'integer'),
|
|
357
334
|
(models.IntegerField, 'integer'),
|
|
358
|
-
(models.SmallIntegerField, 'integer'),
|
|
359
335
|
(models.BooleanField, 'boolean'),
|
|
336
|
+
(models.DateTimeField, 'timestamp'), # 🔴 必须排在 DateField 前面(否则 created_at 报成 date)
|
|
360
337
|
(models.DateField, 'date'),
|
|
361
|
-
(models.
|
|
338
|
+
(models.TimeField, 'time'),
|
|
339
|
+
(models.DurationField, 'interval'),
|
|
362
340
|
(models.DecimalField, 'numeric'),
|
|
363
341
|
(models.FloatField, 'real'),
|
|
364
342
|
(models.JSONField, 'jsonb'),
|
|
343
|
+
(models.UUIDField, 'uuid'),
|
|
344
|
+
(models.BinaryField, 'bytea'),
|
|
345
|
+
(models.GenericIPAddressField, 'inet'),
|
|
346
|
+
# 下面这一档在库里都是 varchar —— 包括"文件字段"(它只是 varchar + 上传逻辑)
|
|
347
|
+
(models.ImageField, 'varchar'), # 🔴 必须排在 FileField 前面
|
|
348
|
+
(models.FileField, 'varchar'),
|
|
349
|
+
(models.EmailField, 'varchar'),
|
|
350
|
+
(models.URLField, 'varchar'),
|
|
351
|
+
(models.SlugField, 'varchar'),
|
|
352
|
+
(models.CharField, 'varchar'),
|
|
353
|
+
(models.TextField, 'text'),
|
|
365
354
|
)
|
|
366
355
|
for cls, name in mapping:
|
|
367
356
|
if isinstance(field, cls):
|
|
368
357
|
return name
|
|
369
|
-
if isinstance(field, (models.CharField, models.SlugField)):
|
|
370
|
-
return 'varchar'
|
|
371
358
|
return 'text'
|
|
372
359
|
|
|
373
360
|
|
{labull_framework-0.1.4 → labull_framework-0.1.4.2}/labull_framework/canvas/static/canvas.css
RENAMED
|
@@ -168,6 +168,44 @@ body {
|
|
|
168
168
|
z-index: 2;
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
+
/* ── 左边那条车道:硬边界 + 跨模块总线(见 canvas.js 的 `boundaryLayer()`) ──────
|
|
172
|
+
* 🔴 边界是**硬**的:`applyView()` 夹住平移,过不去;所以它必须看得见,
|
|
173
|
+
* 否则"怎么拖都拖不动"会像页面卡住了。
|
|
174
|
+
* 🔴 边界**左边**那一块铺一层很淡的底:那是"没有内容、也过不去"的区域。 */
|
|
175
|
+
.boundary-line {
|
|
176
|
+
stroke: var(--line);
|
|
177
|
+
stroke-width: 1.5;
|
|
178
|
+
stroke-dasharray: 7 5;
|
|
179
|
+
}
|
|
180
|
+
.boundary-rail {
|
|
181
|
+
stroke: var(--line);
|
|
182
|
+
stroke-width: 1;
|
|
183
|
+
stroke-dasharray: 2 4;
|
|
184
|
+
opacity: .9;
|
|
185
|
+
}
|
|
186
|
+
.boundary-outside { fill: var(--ink); opacity: .04; }
|
|
187
|
+
.boundary-label {
|
|
188
|
+
fill: var(--muted);
|
|
189
|
+
font-size: 11px;
|
|
190
|
+
user-select: none;
|
|
191
|
+
}
|
|
192
|
+
.boundary-label.is-rail { opacity: .85; }
|
|
193
|
+
/* 跨模块那条线:走法是"横 → 沿总线竖 → 横",与其他线的斜直连一眼能分开 */
|
|
194
|
+
.edge.cross-module { stroke-linecap: square; }
|
|
195
|
+
/* 跨模块"出/进本模块"的那截短线(对端在别的模块里,卡片没画出来):
|
|
196
|
+
* 🔴 画成**点线**:与实线(真的连到了对端)区分开 —— 一眼看出"这条是走到边界为止的"。
|
|
197
|
+
* ⚠️ 与只读那条(`5 4` 虚线)也不同,免得两种含义糊在一起。 */
|
|
198
|
+
.edge.cross-module.is-stub { stroke-dasharray: 1 3; }
|
|
199
|
+
/* 跨模块的关联名放在总线右边那条空道上(框与直连那套同一个样式,只是位置固定) */
|
|
200
|
+
.edge-name.cross-module { text-anchor: middle; }
|
|
201
|
+
/* 短线(对端在别的模块)那几条的标签:**左对齐**放在线上方(见 canvas.js 里那段说明) */
|
|
202
|
+
.edge-name.cross-module.is-stub { text-anchor: start; }
|
|
203
|
+
/* 跨模块短线在总线那一头的"端帽":表示接上了总线,而不是线断了 */
|
|
204
|
+
.edge-cap { fill: none; stroke: var(--ink); stroke-width: 1.6; stroke-linecap: round; }
|
|
205
|
+
.edge-cap.is-added { stroke: var(--added); }
|
|
206
|
+
.edge-cap.is-modified { stroke: var(--modified); }
|
|
207
|
+
.edge-cap.is-deleted { stroke: var(--deleted); }
|
|
208
|
+
|
|
171
209
|
/* 🔴 **默认是黑的**(用户明确要求):连线只有在"这条关联相对基线动过"时才上色 ——
|
|
172
210
|
* 没动过的线不该抢眼,颜色留给"变了的东西"(与卡片、字段行那三档同一套 token)。 */
|
|
173
211
|
.edge {
|
|
@@ -280,9 +318,11 @@ body {
|
|
|
280
318
|
|
|
281
319
|
/* ── 一张表的卡片 ─────────────────────────────────────────────────────── */
|
|
282
320
|
|
|
321
|
+
/* 🔴 卡片宽度:去掉「库类型」那一列之后只需要 **340px**(字段名 150 + 种类 80 + 备注 110)——
|
|
322
|
+
* 三列宽都是写死的(见 `card()` 里那份 `<colgroup>`),所以宽度必须跟它对齐。 */
|
|
283
323
|
.table {
|
|
284
324
|
position: absolute;
|
|
285
|
-
width:
|
|
325
|
+
width: 340px;
|
|
286
326
|
background: var(--card);
|
|
287
327
|
border: 1px solid var(--line);
|
|
288
328
|
border-radius: 10px;
|
|
@@ -292,16 +332,30 @@ body {
|
|
|
292
332
|
}
|
|
293
333
|
.table:hover { box-shadow: 0 2px 4px rgb(15 23 42 / 8%), 0 12px 32px rgb(15 23 42 / 8%); }
|
|
294
334
|
|
|
295
|
-
/*
|
|
296
|
-
* 🔴
|
|
335
|
+
/* 三态:**只有"整张表是新的 / 没了"才整块染底色**(`added` / `deleted`)。
|
|
336
|
+
* 🔴 `modified`(表里**有**字段或关联变过)**不再染色**(用户明确要的:
|
|
337
|
+
* "只有那个字段或者关联变色,而不是整个表变色")—— 逐行 / 逐条线在下面单独上色,
|
|
338
|
+
* 卡片标题旁只挂一个灰的「改 N」,用来在几十张表里找得到是哪张。
|
|
339
|
+
* 🔴 新的表为什么仍然整卡染:基线里根本没有这张表,逐列差异无从谈起,
|
|
340
|
+
* 不染的话"新表"这件事就完全没提示了(它的每一行也会跟着标成 added)。 */
|
|
297
341
|
.table.added { border-color: color-mix(in srgb, var(--added) 45%, var(--line)); background: var(--tint-added); }
|
|
298
|
-
.table.modified { border-color: color-mix(in srgb, var(--modified) 45%, var(--line)); background: var(--tint-modified); }
|
|
299
342
|
.table.deleted { border-color: color-mix(in srgb, var(--deleted) 40%, var(--line)); background: var(--tint-deleted); opacity: .78; }
|
|
300
343
|
.table.added > .head { background: var(--tint-added-strong); box-shadow: inset 3px 0 0 var(--added); }
|
|
301
|
-
.table.modified > .head { background: var(--tint-modified-strong); box-shadow: inset 3px 0 0 var(--modified); }
|
|
302
344
|
.table.deleted > .head { background: var(--tint-deleted-strong); box-shadow: inset 3px 0 0 var(--deleted); }
|
|
303
|
-
/*
|
|
304
|
-
.table:not(.added):not(.
|
|
345
|
+
/* 没变过的表(含"改过"那种)保持素白:颜色留给真的变了的那几行 / 那几条线 */
|
|
346
|
+
.table:not(.added):not(.deleted) > .head { background: var(--head); }
|
|
347
|
+
|
|
348
|
+
/* 标题旁那个灰计数:表里有几处变过(**不是颜色**,只是个索引) */
|
|
349
|
+
.diff-count {
|
|
350
|
+
margin-left: 8px;
|
|
351
|
+
padding: 1px 6px;
|
|
352
|
+
border: 1px solid var(--line);
|
|
353
|
+
border-radius: 999px;
|
|
354
|
+
color: var(--muted);
|
|
355
|
+
font-size: 11px;
|
|
356
|
+
font-family: ui-monospace, Consolas, monospace;
|
|
357
|
+
vertical-align: 1px;
|
|
358
|
+
}
|
|
305
359
|
|
|
306
360
|
.table.is-flash { animation: flash 1.2s ease; }
|
|
307
361
|
@keyframes flash {
|
|
@@ -367,47 +421,43 @@ body {
|
|
|
367
421
|
.note p { margin: 0 0 6px; font-size: 13px; }
|
|
368
422
|
|
|
369
423
|
/* ── 字段行 ──────────────────────────────────────────────────────────────
|
|
370
|
-
* 🔴
|
|
371
|
-
*
|
|
372
|
-
*
|
|
373
|
-
*
|
|
374
|
-
*
|
|
375
|
-
*
|
|
376
|
-
*
|
|
424
|
+
* 🔴 用**真表格布局 + 固定的列宽**(`table-layout: fixed` + `card()` 写的那份 `<colgroup>`):
|
|
425
|
+
* 列宽固定 ⇒ 每行的四列天然对齐(用户要的「每个字段的每个列都能够对齐」),
|
|
426
|
+
* 而且**长备注不会把别的列挤走**(用户要的「行宽可以固定,有需要用户会自己点开看」)——
|
|
427
|
+
* 备注那一格只显示一行、超出用 `…` 截断,想看全文点那一行(`tr.detail` 里有整段)。
|
|
428
|
+
* 原来"每个字段一行、各自一个 grid"的写法连对齐都做不到(列宽按每一行自己的内容算)。
|
|
429
|
+
* (也试过"整张表一个 grid + `display: contents`":轨道共用了,但自动排布会被跨列的
|
|
430
|
+
* detail 行带偏 —— 实测 `customer` 那行的备注格跑到了第一列。所以用表格布局。)
|
|
431
|
+
* 🔴 列序翻转(备注优先 ⇄ 字段名优先)**不靠 CSS 的 `order`**(`<td>` 上根本不生效,
|
|
432
|
+
* 那是 grid 才有的),改由 `fieldRow()` **按当前模式决定 append 顺序**,宽度也跟着换一套。
|
|
377
433
|
*/
|
|
378
|
-
table.cols {
|
|
379
|
-
table.cols
|
|
380
|
-
table.cols tr.field {
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
434
|
+
table.cols { width: 100%; table-layout: fixed; border-collapse: collapse; }
|
|
435
|
+
table.cols tr.detail { display: none; }
|
|
436
|
+
table.cols tr.field.is-open + tr.detail { display: table-row; }
|
|
437
|
+
table.cols tr.detail > td { padding: 6px 10px 10px 22px; white-space: normal; }
|
|
438
|
+
/* 「关联字段(外键列)」那一组默认**合上**(要再打开,见 `card()` 里那个 toggle 行) */
|
|
439
|
+
table.cols tbody[hidden] { display: none; }
|
|
440
|
+
table.cols tr.fk-toggle > td {
|
|
441
|
+
cursor: pointer;
|
|
442
|
+
color: var(--muted);
|
|
443
|
+
font-size: 11.5px;
|
|
444
|
+
border-top: 1px dashed var(--line);
|
|
445
|
+
}
|
|
446
|
+
table.cols tr.fk-toggle .caret-mini { display: inline-block; font-style: normal; transition: transform .12s; }
|
|
447
|
+
table.cols tr.fk-toggle.is-open .caret-mini { transform: rotate(90deg); }
|
|
389
448
|
|
|
390
449
|
table.cols td {
|
|
391
|
-
padding: 4px
|
|
450
|
+
padding: 4px 8px;
|
|
392
451
|
border-top: 1px solid var(--line-soft);
|
|
393
452
|
font-size: 12.5px;
|
|
394
|
-
|
|
453
|
+
/* 🔴 固定列宽 + 一行截断:三列都 nowrap,超了给 `…`(`title` 里挂着全文,鼠标停一下也能看) */
|
|
454
|
+
white-space: nowrap;
|
|
455
|
+
overflow: hidden;
|
|
456
|
+
text-overflow: ellipsis;
|
|
395
457
|
}
|
|
396
458
|
table.cols tr.field:first-child td { border-top: 0; }
|
|
397
459
|
|
|
398
|
-
/*
|
|
399
|
-
* 只翻 `order` 不够 —— 列宽也得换,否则备注列还是那条窄缝(等于没翻)。
|
|
400
|
-
* 🔴 备注列给**固定宽**,不给 `fr`:它是这张网格里**唯一**的弹性轨道,
|
|
401
|
-
* `0.5fr` 和 `9fr` 算出来一样宽(都吃掉全部剩余)—— 真踩过,改了半天没反应。
|
|
402
|
-
* 固定 128px 之后,字段名那一列自然贴到左边,右侧多出来的留白(收窄卡片或拖宽都行)。 */
|
|
403
|
-
#canvas.is-note-first table.cols tr.field {
|
|
404
|
-
grid-template-columns:
|
|
405
|
-
116px minmax(min-content, auto) minmax(min-content, auto) minmax(min-content, auto);
|
|
406
|
-
justify-content: start;
|
|
407
|
-
}
|
|
408
|
-
#canvas.is-note-first td.brief { order: -1; }
|
|
409
|
-
/* 备注优先时把卡片放宽一点:四列里有一列是整句说明,320px 是字段名优先那套的宽度。 */
|
|
410
|
-
#canvas.is-note-first .table { width: 380px; }
|
|
460
|
+
/* 备注优先时卡片**不用再放宽**:两种模式都是 400px(列宽固定,见 `.table` 那一段的说明)。 */
|
|
411
461
|
|
|
412
462
|
/* 一格备注都没有时那个破折号:压暗,别让人以为"这里有内容" */
|
|
413
463
|
td.brief.empty { color: var(--line); }
|
|
@@ -453,13 +503,9 @@ td.kind .mark {
|
|
|
453
503
|
.mark.amber { color: var(--tone-amber); }
|
|
454
504
|
.mark.teal { color: var(--tone-teal); }
|
|
455
505
|
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
white-space: nowrap;
|
|
460
|
-
font-family: ui-monospace, Consolas, monospace;
|
|
461
|
-
font-size: 11.5px;
|
|
462
|
-
}
|
|
506
|
+
/* 🔴 「库类型」那一列**去掉了**(用户要的:"这些都不需要了")——
|
|
507
|
+
* `bigint` / `text` / `varchar` 这些是"库里怎么存的",人看的是左边那个"种类"小标
|
|
508
|
+
* (整数 / 长文本 / 文件 / 时间…)。真要看库类型时,点开那一行,详情里有。 */
|
|
463
509
|
|
|
464
510
|
td.brief { color: var(--muted); }
|
|
465
511
|
td.brief.muted { opacity: .75; }
|
|
@@ -519,6 +565,13 @@ tr.detail .note-text { color: var(--muted); }
|
|
|
519
565
|
cursor: pointer;
|
|
520
566
|
}
|
|
521
567
|
.rel:hover { background: #f1f5f9; }
|
|
568
|
+
/* 关联那一行也按"这条动过没有"上色(与画布上那条线同一个判据):**只染这一行** */
|
|
569
|
+
.rel.is-added { background: var(--tint-added-strong); }
|
|
570
|
+
.rel.is-modified { background: var(--tint-modified-strong); }
|
|
571
|
+
.rel.is-deleted { background: var(--tint-deleted-strong); text-decoration: line-through; text-decoration-color: color-mix(in srgb, var(--deleted) 55%, transparent); }
|
|
572
|
+
.rel.is-added .rel-name { color: var(--added); }
|
|
573
|
+
.rel.is-modified .rel-name { color: var(--modified); }
|
|
574
|
+
.rel.is-deleted .rel-name { color: var(--deleted); }
|
|
522
575
|
.rel .rel-name { font-family: ui-monospace, Consolas, monospace; }
|
|
523
576
|
.rel .rel-to { margin-left: auto; color: var(--accent); font-size: 12px; }
|
|
524
577
|
|