@cardenelabs/cdl 0.73.0 → 0.75.0
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.
- package/CHANGELOG.md +76 -1
- package/dist/index.cjs +301 -196
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +301 -196
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +361 -256
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +361 -256
- package/dist/react.js.map +1 -1
- package/package.json +1 -1
- package/src/kinds/shape-blockchain.tsx +129 -47
- package/src/kinds/shape-commerce.tsx +45 -14
- package/src/kinds/shape-finance.tsx +73 -19
- package/src/kinds/shape-people.tsx +3 -3
- package/src/kinds/shape-region.tsx +93 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cardenelabs/cdl",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.75.0",
|
|
4
4
|
"description": "CDL (Chainome Diagram Language). Mermaid-like declarative DSL that compiles to animated SVG diagrams. Built for blockchain / Solidity flows, generic enough for sequence / flow / state / ER / topology diagrams.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "cardene777",
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
import type { JSX } from "react";
|
|
2
2
|
import type { LaidNode } from "../types";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
fitArt,
|
|
5
|
+
labelPlan,
|
|
6
|
+
shapeRegion,
|
|
7
|
+
textWidth,
|
|
8
|
+
打ち消しの倍率,
|
|
9
|
+
絵の中の字の幅,
|
|
10
|
+
type ArtExtent,
|
|
11
|
+
type 打ち消す字,
|
|
12
|
+
} from "./shape-region";
|
|
4
13
|
import { 幅で切る } from "./box-lines";
|
|
5
|
-
import { MONO_ADVANCE_RATIO, displayWidth } from "./row-align";
|
|
6
14
|
import { 字引きを作る, type CdlLang, type CdlTextKey } from "../lang";
|
|
7
15
|
|
|
8
16
|
/**
|
|
@@ -36,28 +44,6 @@ const 値の字 = 11;
|
|
|
36
44
|
/** 5 行を並べる間隔と、見出しが乗る帯の高さ。 打ち消しの上限をここから出す (#871) */
|
|
37
45
|
const 行の間隔 = 22;
|
|
38
46
|
const 見出しの帯 = 32;
|
|
39
|
-
/** 打ち消した字が帯のどこまでを占めてよいか。 超えると上下の行や帯の縁に触れる */
|
|
40
|
-
const 帯に対する上限 = 0.8;
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* 縮んだ分を字の指定で打ち消す倍率 (#871)。
|
|
44
|
-
*
|
|
45
|
-
* この絵は 240 x 220 で組んでから、箱に収まる倍率で丸ごと縮む。 字も一緒に縮むので、
|
|
46
|
-
* 指定 10.5 が `k = 0.719` の図で 7.55 になり、画面で読める下限 (8px) を割っていた。
|
|
47
|
-
*
|
|
48
|
-
* **上限は絵の中の帯から出す** = 固定値にすると、絵の寸法を変えた日に効き方だけが変わる。
|
|
49
|
-
* 5 行は 22 ずつ空けて並べ、見出しは高さ 32 の帯に乗る。
|
|
50
|
-
*
|
|
51
|
-
* 1 を下回らない = 縮んでいない図 (`k = 1`) で字を小さくしない。
|
|
52
|
-
*/
|
|
53
|
-
function 打ち消しの倍率(k: number): number {
|
|
54
|
-
const 戻し = Number.isFinite(k) && k > 0 ? 1 / k : 1;
|
|
55
|
-
const 上限 = Math.min(
|
|
56
|
-
(行の間隔 * 帯に対する上限) / 値の字,
|
|
57
|
-
(見出しの帯 * 帯に対する上限) / 見出しの字,
|
|
58
|
-
);
|
|
59
|
-
return Math.max(1, Math.min(戻し, 上限));
|
|
60
|
-
}
|
|
61
47
|
const BLOCK_SHADOW = 6;
|
|
62
48
|
|
|
63
49
|
const NFT_W = 220;
|
|
@@ -70,6 +56,19 @@ const CHAIN_BLOCK_H = 66;
|
|
|
70
56
|
const CHAIN_LINK_W = 12;
|
|
71
57
|
const CHAIN_SHADOW = 3;
|
|
72
58
|
const CHAIN_BLOCK_SW = 2.5;
|
|
59
|
+
/** 連鎖の箱の頭の帯の高さ。 番号がここに乗る (#887 で打ち消しの帯に使うため定数へ出した) */
|
|
60
|
+
const CHAIN_HEAD_H = 16;
|
|
61
|
+
/** 箱の中で字が使える幅。 左右に 4 ずつ余白を置く */
|
|
62
|
+
const CHAIN_TEXT_W = CHAIN_BLOCK_W - 8;
|
|
63
|
+
/** 箱の中の 2 行 (中央の記号と下の字) の baseline の間隔 */
|
|
64
|
+
const CHAIN_ROW_GAP = 14;
|
|
65
|
+
/** 連鎖の箱の中の字の指定 (#887 で打ち消しの計算に使うため定数へ出した) */
|
|
66
|
+
const CHAIN_NO_SIZE = 10;
|
|
67
|
+
const CONTRACT_CALL_SIZE = 11;
|
|
68
|
+
const NFT_ID_SIZE = 15;
|
|
69
|
+
const CHAIN_HASH_SIZE = 7;
|
|
70
|
+
const BTC_NO_SIZE = 9;
|
|
71
|
+
const ETH_NO_SIZE = 9;
|
|
73
72
|
|
|
74
73
|
const NODE_HEX_R = 44;
|
|
75
74
|
const NODE_PEER_R = 12;
|
|
@@ -237,7 +236,23 @@ export function ShapeSmartContractNode({ node, active, lang }: ShapeProps): JSX.
|
|
|
237
236
|
gearPts.push(`${gearCx + Math.cos(a3) * gearTipR},${gearCy + Math.sin(a3) * gearTipR}`);
|
|
238
237
|
gearPts.push(`${gearCx + Math.cos(a4) * gearBodyR},${gearCy + Math.sin(a4) * gearBodyR}`);
|
|
239
238
|
}
|
|
240
|
-
|
|
239
|
+
/*
|
|
240
|
+
* 打ち消しの上限を出す帯 (#887)。 呼び出し行は書類の下寄りに 1 行だけ置くので、
|
|
241
|
+
* 幅は書類の内側 (左右 16 ずつ)、高さは行を並べる間隔 18 を使う。
|
|
242
|
+
*
|
|
243
|
+
* 字引きで日英が切り替わる (`function execute()` 18 字 と 自動で実行する 7 字) ため、
|
|
244
|
+
* 描く字そのものを渡して幅を数える。
|
|
245
|
+
*/
|
|
246
|
+
const 打ち消す字ら: 打ち消す字[] = [
|
|
247
|
+
{
|
|
248
|
+
text: 字引("smartContract.call"),
|
|
249
|
+
size: CONTRACT_CALL_SIZE,
|
|
250
|
+
帯: { 幅: docW - 32, 高さ: 18 },
|
|
251
|
+
},
|
|
252
|
+
];
|
|
253
|
+
const art = (倍率: number): JSX.Element => {
|
|
254
|
+
const 倍 = 打ち消しの倍率(倍率, 打ち消す字ら);
|
|
255
|
+
return (
|
|
241
256
|
<g>
|
|
242
257
|
<path data-cdl-role="node-body" d={path} {...frame} strokeLinejoin="round" />
|
|
243
258
|
<path d={foldPath} fill="none" stroke={frame.stroke} strokeWidth={frame.strokeWidth} strokeLinejoin="round" />
|
|
@@ -246,7 +261,7 @@ export function ShapeSmartContractNode({ node, active, lang }: ShapeProps): JSX.
|
|
|
246
261
|
<rect key={i} x={x + 16} y={ly - 3} width={docW - 32 - i * 22} height={5} rx={1} fill="var(--cdl-divider, #d4d4d8)" fillOpacity={0.7} stroke="none" />
|
|
247
262
|
))}
|
|
248
263
|
{/* function signature */}
|
|
249
|
-
<text x={x + 16} y={y + docH - 46} fontSize={
|
|
264
|
+
<text data-cdl-counter-scaled="1" x={x + 16} y={y + docH - 46} fontSize={CONTRACT_CALL_SIZE * 倍} fontFamily="ui-monospace, SFMono-Regular, Menlo, monospace" fill="var(--cdl-tone-accent, #2d6a8f)">
|
|
250
265
|
{字引("smartContract.call")}
|
|
251
266
|
</text>
|
|
252
267
|
{/* gear (auto-execution 記号) */}
|
|
@@ -261,7 +276,8 @@ export function ShapeSmartContractNode({ node, active, lang }: ShapeProps): JSX.
|
|
|
261
276
|
</polygon>
|
|
262
277
|
<circle cx={gearCx} cy={gearCy} r={gearBodyR * 0.4} fill="var(--cdl-node-fill, #ffffff)" stroke="none" />
|
|
263
278
|
</g>
|
|
264
|
-
|
|
279
|
+
);
|
|
280
|
+
};
|
|
265
281
|
return (
|
|
266
282
|
<g>
|
|
267
283
|
{fitArt(r, smartContractExtent(frame.strokeWidth), art)}
|
|
@@ -281,8 +297,7 @@ export function ShapeSmartContractNode({ node, active, lang }: ShapeProps): JSX.
|
|
|
281
297
|
* どちらの書体で描かれても実物以上に出る側へ倒す = 下回ると「収まっていない物を収まっていると
|
|
282
298
|
* 判定」 する向きに外れる (`row-align.ts` の `rowColumnWidth` と同じ考え方)。
|
|
283
299
|
*/
|
|
284
|
-
const 字の幅 = (text: string, size: number): number =>
|
|
285
|
-
Math.max(displayWidth(text) * size * MONO_ADVANCE_RATIO, textWidth(text, size));
|
|
300
|
+
const 字の幅 = (text: string, size: number): number => 絵の中の字の幅(text, size);
|
|
286
301
|
|
|
287
302
|
/**
|
|
288
303
|
* 絵の中の 5 行の既定値。 書き手が渡さなかった欄はこれで描く (#469)。
|
|
@@ -356,8 +371,28 @@ export function ShapeBlockchainBlockNode({ node, active, lang }: ShapeProps): JS
|
|
|
356
371
|
* **幅の予算も打ち消した後の大きさで計算する** = 字だけ大きくして切る位置を元の大きさの
|
|
357
372
|
* まま置くと、切った字が枠から出る。
|
|
358
373
|
*/
|
|
374
|
+
/*
|
|
375
|
+
* 打ち消しの上限を出す帯 (#886)。 **絵の定数から渡す**。
|
|
376
|
+
*
|
|
377
|
+
* 見出しは高さ 32 の帯に乗り、5 行は 22 ずつ空けて並ぶ。 幅は行の内側 (`bw - 28`) で、
|
|
378
|
+
* 値は名前の分を引いた残り = 名前と値が同じ行に並ぶため。
|
|
379
|
+
*
|
|
380
|
+
* 値の幅は **打ち消す前の名前の幅** で引く。 打ち消した後の幅で引くと、上限を出すのに
|
|
381
|
+
* 上限が要る形になる。 名前は打ち消しで広がるので、その分は帯に対する上限 (8 割) が吸う。
|
|
382
|
+
*/
|
|
383
|
+
const 打ち消す字ら: 打ち消す字[] = [
|
|
384
|
+
{ text: 見出し, size: 見出しの字, 帯: { 幅: 見出しの幅, 高さ: 見出しの帯 } },
|
|
385
|
+
...fields.flatMap((f): 打ち消す字[] => [
|
|
386
|
+
{ text: f.label, size: 名の字, 帯: { 幅: bw - 28, 高さ: 行の間隔 } },
|
|
387
|
+
{
|
|
388
|
+
text: f.value,
|
|
389
|
+
size: 値の字,
|
|
390
|
+
帯: { 幅: bw - 28 - 字の幅(f.label, 名の字) - 8, 高さ: 行の間隔 },
|
|
391
|
+
},
|
|
392
|
+
]),
|
|
393
|
+
];
|
|
359
394
|
const art = (倍率: number): JSX.Element => {
|
|
360
|
-
const 倍 = 打ち消しの倍率(
|
|
395
|
+
const 倍 = 打ち消しの倍率(倍率, 打ち消す字ら);
|
|
361
396
|
const 題の大きさ = 見出しの字 * 倍;
|
|
362
397
|
const 名の大きさ = 名の字 * 倍;
|
|
363
398
|
const 値の大きさ = 値の字 * 倍;
|
|
@@ -368,17 +403,17 @@ export function ShapeBlockchainBlockNode({ node, active, lang }: ShapeProps): JS
|
|
|
368
403
|
<rect data-cdl-role="node-body" x={x} y={y} width={bw} height={bh} rx={8} {...frame} />
|
|
369
404
|
{/* header bar */}
|
|
370
405
|
<path d={`M ${x} ${y + 32} L ${x} ${y + 8} Q ${x} ${y}, ${x + 8} ${y} L ${x + bw - 8} ${y} Q ${x + bw} ${y}, ${x + bw} ${y + 8} L ${x + bw} ${y + 32} Z`} fill="var(--cdl-tone-accent, #2d6a8f)" fillOpacity={0.9} stroke="none" />
|
|
371
|
-
<text data-cdl-role="blockchain-block-title" x={x + 14} y={y + 22} fontSize={題の大きさ} fontWeight={700} fontFamily="ui-monospace, SFMono-Regular, Menlo, monospace" fill="#ffffff">
|
|
406
|
+
<text data-cdl-role="blockchain-block-title" data-cdl-counter-scaled="1" x={x + 14} y={y + 22} fontSize={題の大きさ} fontWeight={700} fontFamily="ui-monospace, SFMono-Regular, Menlo, monospace" fill="#ffffff">
|
|
372
407
|
{幅で切る(見出し, 題の大きさ, 見出しの幅, 字の幅)}
|
|
373
408
|
</text>
|
|
374
409
|
<circle cx={x + bw - 16} cy={y + 16} r={5.5} fill="#7cd88f" stroke="#ffffff" strokeWidth={1.5} />
|
|
375
410
|
{/* fields */}
|
|
376
411
|
{fields.map((f, i) => (
|
|
377
412
|
<g key={i}>
|
|
378
|
-
<text x={x + 14} y={y + 54 + i * 行の間隔} fontSize={名の大きさ} fontFamily="ui-monospace, SFMono-Regular, Menlo, monospace" fill="var(--cdl-text-dim, #5a6270)">
|
|
413
|
+
<text data-cdl-counter-scaled="1" x={x + 14} y={y + 54 + i * 行の間隔} fontSize={名の大きさ} fontFamily="ui-monospace, SFMono-Regular, Menlo, monospace" fill="var(--cdl-text-dim, #5a6270)">
|
|
379
414
|
{f.label}
|
|
380
415
|
</text>
|
|
381
|
-
<text data-cdl-role={`blockchain-block-${f.key}`} x={x + bw - 14} y={y + 54 + i * 行の間隔} fontSize={値の大きさ} fontFamily="ui-monospace, SFMono-Regular, Menlo, monospace" fontWeight={600} textAnchor="end" fill="var(--cdl-text, #1a1f2a)">
|
|
416
|
+
<text data-cdl-role={`blockchain-block-${f.key}`} data-cdl-counter-scaled="1" x={x + bw - 14} y={y + 54 + i * 行の間隔} fontSize={値の大きさ} fontFamily="ui-monospace, SFMono-Regular, Menlo, monospace" fontWeight={600} textAnchor="end" fill="var(--cdl-text, #1a1f2a)">
|
|
382
417
|
{幅で切る(f.value, 値の大きさ, bw - 28 - 字の幅(f.label, 名の大きさ) - 8, 字の幅)}
|
|
383
418
|
</text>
|
|
384
419
|
<line x1={x + 14} y1={y + 60 + i * 行の間隔} x2={x + bw - 14} y2={y + 60 + i * 行の間隔} stroke="var(--cdl-divider, #d4d4d8)" strokeWidth={0.5} opacity={0.5} />
|
|
@@ -408,7 +443,19 @@ export function ShapeBlockchainNode({ node, active }: ShapeProps): JSX.Element {
|
|
|
408
443
|
const linkW = CHAIN_LINK_W;
|
|
409
444
|
const totalW = blockCount * blockW + (blockCount - 1) * linkW;
|
|
410
445
|
const startX = cx - totalW / 2;
|
|
411
|
-
|
|
446
|
+
/*
|
|
447
|
+
* 打ち消しの上限を出す帯 (#887)。 番号は頭の帯 (高さ 16) に乗り、下の字は中央の記号との
|
|
448
|
+
* 間隔 14 に収まる。 幅はどちらも箱の内側。
|
|
449
|
+
*
|
|
450
|
+
* **中央の記号 (`#`) は打ち消さない**。 箱の中央に大きく置いた飾りで、戻すと箱から出る。
|
|
451
|
+
*/
|
|
452
|
+
const 打ち消す字ら: 打ち消す字[] = [
|
|
453
|
+
{ text: "#420", size: CHAIN_NO_SIZE, 帯: { 幅: CHAIN_TEXT_W, 高さ: CHAIN_HEAD_H } },
|
|
454
|
+
{ text: "0x…", size: CHAIN_HASH_SIZE, 帯: { 幅: CHAIN_TEXT_W, 高さ: CHAIN_ROW_GAP } },
|
|
455
|
+
];
|
|
456
|
+
const art = (倍率: number): JSX.Element => {
|
|
457
|
+
const 倍 = 打ち消しの倍率(倍率, 打ち消す字ら);
|
|
458
|
+
return (
|
|
412
459
|
<g>
|
|
413
460
|
{Array.from({ length: blockCount }, (_, i) => i).map((i) => {
|
|
414
461
|
const bx = startX + i * (blockW + linkW);
|
|
@@ -435,21 +482,22 @@ export function ShapeBlockchainNode({ node, active }: ShapeProps): JSX.Element {
|
|
|
435
482
|
stroke={frame.stroke}
|
|
436
483
|
strokeWidth={isCurrent ? 2.5 : 1.5}
|
|
437
484
|
/>
|
|
438
|
-
<rect x={bx} y={cy - blockH / 2} width={blockW} height={
|
|
439
|
-
<text x={bx + blockW / 2} y={cy - blockH / 2 + 12} fontSize={
|
|
485
|
+
<rect x={bx} y={cy - blockH / 2} width={blockW} height={CHAIN_HEAD_H} rx={4} fill={isCurrent ? "#1a4a68" : "var(--cdl-divider, #d4d4d8)"} fillOpacity={isCurrent ? 1 : 0.4} stroke="none" />
|
|
486
|
+
<text data-cdl-counter-scaled="1" x={bx + blockW / 2} y={cy - blockH / 2 + 12} fontSize={CHAIN_NO_SIZE * 倍} fontFamily="ui-monospace, SFMono-Regular, Menlo, monospace" fontWeight={700} textAnchor="middle" fill={isCurrent ? "#ffffff" : "var(--cdl-text-dim, #5a6270)"}>
|
|
440
487
|
#{420 + i}
|
|
441
488
|
</text>
|
|
442
|
-
<text x={bx + blockW / 2} y={cy + 8} fontSize={14} fontWeight={700} textAnchor="middle" fill={isCurrent ? "#ffffff" : "var(--cdl-tone-accent, #2d6a8f)"} fontFamily="Georgia, serif">
|
|
489
|
+
<text data-cdl-counter-scaled="0" x={bx + blockW / 2} y={cy + 8} fontSize={14} fontWeight={700} textAnchor="middle" fill={isCurrent ? "#ffffff" : "var(--cdl-tone-accent, #2d6a8f)"} fontFamily="Georgia, serif">
|
|
443
490
|
#
|
|
444
491
|
</text>
|
|
445
|
-
<text x={bx + blockW / 2} y={cy + 22} fontSize={
|
|
492
|
+
<text data-cdl-counter-scaled="1" x={bx + blockW / 2} y={cy + 22} fontSize={CHAIN_HASH_SIZE * 倍} fontFamily="ui-monospace, SFMono-Regular, Menlo, monospace" textAnchor="middle" fill={isCurrent ? "#ffffff" : "var(--cdl-text-dim, #5a6270)"} opacity={0.9}>
|
|
446
493
|
0x…
|
|
447
494
|
</text>
|
|
448
495
|
</g>
|
|
449
496
|
);
|
|
450
497
|
})}
|
|
451
498
|
</g>
|
|
452
|
-
|
|
499
|
+
);
|
|
500
|
+
};
|
|
453
501
|
return (
|
|
454
502
|
<g>
|
|
455
503
|
{fitArt(r, chainExtent(), art)}
|
|
@@ -471,7 +519,17 @@ export function ShapeBitcoinChainNode({ node, active }: ShapeProps): JSX.Element
|
|
|
471
519
|
const linkW = CHAIN_LINK_W;
|
|
472
520
|
const totalW = blockCount * blockW + (blockCount - 1) * linkW;
|
|
473
521
|
const startX = cx - totalW / 2;
|
|
474
|
-
|
|
522
|
+
/*
|
|
523
|
+
* 打ち消しの上限を出す帯 (#887)。 番号は箱の下半分に置き、中央の `₿` との間隔 20 に収まる。
|
|
524
|
+
*
|
|
525
|
+
* **`₿` は打ち消さない** (指定 30 の飾りで、箱の高さ 66 に対して既に大きい)。
|
|
526
|
+
*/
|
|
527
|
+
const 打ち消す字ら: 打ち消す字[] = [
|
|
528
|
+
{ text: "#820", size: BTC_NO_SIZE, 帯: { 幅: CHAIN_TEXT_W, 高さ: 20 } },
|
|
529
|
+
];
|
|
530
|
+
const art = (倍率: number): JSX.Element => {
|
|
531
|
+
const 倍 = 打ち消しの倍率(倍率, 打ち消す字ら);
|
|
532
|
+
return (
|
|
475
533
|
<g>
|
|
476
534
|
{Array.from({ length: blockCount }, (_, i) => i).map((i) => {
|
|
477
535
|
const bx = startX + i * (blockW + linkW);
|
|
@@ -491,17 +549,18 @@ export function ShapeBitcoinChainNode({ node, active }: ShapeProps): JSX.Element
|
|
|
491
549
|
stroke={btcOrange}
|
|
492
550
|
strokeWidth={isCurrent ? 2.5 : 1.5}
|
|
493
551
|
/>
|
|
494
|
-
<text x={bx + blockW / 2} y={cy - 4} fontSize={30} fontWeight={700} textAnchor="middle" fill={isCurrent ? "#ffffff" : btcOrange} fontFamily="Georgia, serif">
|
|
552
|
+
<text data-cdl-counter-scaled="0" x={bx + blockW / 2} y={cy - 4} fontSize={30} fontWeight={700} textAnchor="middle" fill={isCurrent ? "#ffffff" : btcOrange} fontFamily="Georgia, serif">
|
|
495
553
|
₿
|
|
496
554
|
</text>
|
|
497
|
-
<text x={bx + blockW / 2} y={cy + 16} fontSize={
|
|
555
|
+
<text data-cdl-counter-scaled="1" x={bx + blockW / 2} y={cy + 16} fontSize={BTC_NO_SIZE * 倍} fontFamily="ui-monospace, SFMono-Regular, Menlo, monospace" fontWeight={700} textAnchor="middle" fill={isCurrent ? "#ffffff" : "var(--cdl-text-dim, #5a6270)"}>
|
|
498
556
|
#{820 + i}
|
|
499
557
|
</text>
|
|
500
558
|
</g>
|
|
501
559
|
);
|
|
502
560
|
})}
|
|
503
561
|
</g>
|
|
504
|
-
|
|
562
|
+
);
|
|
563
|
+
};
|
|
505
564
|
return (
|
|
506
565
|
<g>
|
|
507
566
|
{fitArt(r, chainExtent(), art)}
|
|
@@ -523,6 +582,15 @@ export function ShapeEthereumChainNode({ node, active }: ShapeProps): JSX.Elemen
|
|
|
523
582
|
const linkW = CHAIN_LINK_W;
|
|
524
583
|
const totalW = blockCount * blockW + (blockCount - 1) * linkW;
|
|
525
584
|
const startX = cx - totalW / 2;
|
|
585
|
+
/*
|
|
586
|
+
* **番号は打ち消さない** (#887)。 6 桁の番号は指定 9 でも幅の見積りが 46 になり、
|
|
587
|
+
* 箱の中で字が使える幅 42 (`CHAIN_TEXT_W`) を縮む前から超えている = 打ち消す余地が無い
|
|
588
|
+
* (`textWidth` は等幅の指定を無視して比例の書体で測る。 dragon の `cdl-theme.css` が
|
|
589
|
+
* `--d-body` を `!important` で当てるため、描かれるのは比例の書体になる)。
|
|
590
|
+
*
|
|
591
|
+
* 4 桁の `shape-bitcoin-chain` は同じ帯に収まるので打ち消しに乗っている。
|
|
592
|
+
* 縮む前から帯を超えていること自体は別の課題 (cardene777/cdl#885 と同じ形)。
|
|
593
|
+
*/
|
|
526
594
|
const art = (
|
|
527
595
|
<g>
|
|
528
596
|
{Array.from({ length: blockCount }, (_, i) => i).map((i) => {
|
|
@@ -548,7 +616,7 @@ export function ShapeEthereumChainNode({ node, active }: ShapeProps): JSX.Elemen
|
|
|
548
616
|
/>
|
|
549
617
|
{/* Ethereum Diamond ロゴ */}
|
|
550
618
|
<EthereumDiamond cx={bx + blockW / 2} cy={cy - 6} h={16} colors={iconColors} />
|
|
551
|
-
<text x={bx + blockW / 2} y={cy + 22} fontSize={
|
|
619
|
+
<text data-cdl-counter-scaled="0" x={bx + blockW / 2} y={cy + 22} fontSize={ETH_NO_SIZE} fontFamily="ui-monospace, SFMono-Regular, Menlo, monospace" fontWeight={700} textAnchor="middle" fill={isCurrent ? "#ffffff" : "var(--cdl-text-dim, #5a6270)"}>
|
|
552
620
|
#{21_400 + i}
|
|
553
621
|
</text>
|
|
554
622
|
</g>
|
|
@@ -771,7 +839,19 @@ export function ShapeNftNode({ node, active }: ShapeProps): JSX.Element {
|
|
|
771
839
|
const artH = cardH * 0.72;
|
|
772
840
|
const artCx = x + cardW / 2;
|
|
773
841
|
const artCy = y + artH / 2;
|
|
774
|
-
|
|
842
|
+
/*
|
|
843
|
+
* 打ち消しの上限を出す帯 (#887)。 番号は下の帯に置く。 高さは帯 (cardH - artH = 67)、
|
|
844
|
+
* 幅は左の余白 16 と右の丸 (半径 10、中心が cardW - 20) を避けた分。
|
|
845
|
+
*
|
|
846
|
+
* **絵の中央の `NFT` (指定 68) は打ち消さない**。 上の帯いっぱいに置いた飾りで、
|
|
847
|
+
* 戻すと帯から出る (実測 = 余り 0.92 で既に使い切っている)。
|
|
848
|
+
*/
|
|
849
|
+
const 打ち消す字ら: 打ち消す字[] = [
|
|
850
|
+
{ text: "#1024", size: NFT_ID_SIZE, 帯: { 幅: cardW - 16 - 34, 高さ: cardH - artH } },
|
|
851
|
+
];
|
|
852
|
+
const art = (倍率: number): JSX.Element => {
|
|
853
|
+
const 倍 = 打ち消しの倍率(倍率, 打ち消す字ら);
|
|
854
|
+
return (
|
|
775
855
|
<g>
|
|
776
856
|
{/* shadow */}
|
|
777
857
|
<rect x={x + 4} y={y + 4} width={cardW} height={cardH} rx={14} fill={frame.stroke} opacity={0.2} stroke="none" />
|
|
@@ -786,6 +866,7 @@ export function ShapeNftNode({ node, active }: ShapeProps): JSX.Element {
|
|
|
786
866
|
/>
|
|
787
867
|
{/* 巨大 NFT 文字 (art 中央、 accent 色) */}
|
|
788
868
|
<text
|
|
869
|
+
data-cdl-counter-scaled="0"
|
|
789
870
|
x={artCx}
|
|
790
871
|
y={artCy + 24}
|
|
791
872
|
fontSize={68}
|
|
@@ -800,7 +881,7 @@ export function ShapeNftNode({ node, active }: ShapeProps): JSX.Element {
|
|
|
800
881
|
{/* 下部 info bar */}
|
|
801
882
|
<line x1={x} y1={y + artH} x2={x + cardW} y2={y + artH} stroke={frame.stroke} strokeWidth={1} opacity={0.5} />
|
|
802
883
|
{/* token id (左) */}
|
|
803
|
-
<text x={x + 16} y={y + artH + 30} fontSize={
|
|
884
|
+
<text data-cdl-counter-scaled="1" x={x + 16} y={y + artH + 30} fontSize={NFT_ID_SIZE * 倍} fontWeight={700} fill="var(--cdl-text, #1a1f2a)" fontFamily="ui-monospace, SFMono-Regular, Menlo, monospace">
|
|
804
885
|
#1024
|
|
805
886
|
</text>
|
|
806
887
|
{/* verified check (右) */}
|
|
@@ -809,7 +890,8 @@ export function ShapeNftNode({ node, active }: ShapeProps): JSX.Element {
|
|
|
809
890
|
<path d="M -4 0 L -1 3 L 4 -3" fill="none" stroke="#ffffff" strokeWidth={2.5} strokeLinecap="round" strokeLinejoin="round" />
|
|
810
891
|
</g>
|
|
811
892
|
</g>
|
|
812
|
-
|
|
893
|
+
);
|
|
894
|
+
};
|
|
813
895
|
return (
|
|
814
896
|
<g>
|
|
815
897
|
{fitArt(r, nftExtent(frame.strokeWidth), art)}
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import type { JSX } from "react";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
shapeRegion,
|
|
4
|
+
labelPlan,
|
|
5
|
+
fitArt,
|
|
6
|
+
textWidth,
|
|
7
|
+
打ち消しの倍率,
|
|
8
|
+
type 打ち消す字,
|
|
9
|
+
} from "./shape-region";
|
|
3
10
|
import { MONO_ADVANCE_RATIO, displayWidth } from "./row-align";
|
|
4
11
|
import type { LaidNode } from "../types";
|
|
5
12
|
import { 字引きを作る, type CdlLang } from "../lang";
|
|
@@ -304,7 +311,7 @@ export function ShapeWarehouseNode({ node, active, lang }: ShapeProps): JSX.Elem
|
|
|
304
311
|
<rect data-cdl-role="node-body" x={x} y={y + roofH} width={bw} height={bh - roofH - 12} fill="#a89d8f" stroke="#5a6270" strokeWidth={frame.strokeWidth} />
|
|
305
312
|
{/* WAREHOUSE 看板 (赤帯) */}
|
|
306
313
|
<rect x={x} y={y + roofH} width={bw} height={signH} fill="#c15a4a" stroke="#8b3f2f" strokeWidth={1.5} />
|
|
307
|
-
<text x={cx} y={y + roofH + 17} fontSize={12} fontWeight={900} letterSpacing={6} textAnchor="middle" fill="#ffffff">{字引("warehouse.sign")}</text>
|
|
314
|
+
<text data-cdl-counter-scaled="0" x={cx} y={y + roofH + 17} fontSize={12} fontWeight={900} letterSpacing={6} textAnchor="middle" fill="#ffffff">{字引("warehouse.sign")}</text>
|
|
308
315
|
{/* 中央大 shutter (rib 縞) */}
|
|
309
316
|
<rect x={shutterX} y={shutterY} width={shutterW} height={shutterH} fill="#8b949e" stroke={accentDarker} strokeWidth={2} />
|
|
310
317
|
{/* shutter 上部 shade (立体感) */}
|
|
@@ -501,6 +508,12 @@ const API_ROWS = 3;
|
|
|
501
508
|
/** 板の大きさ。 高さの下限は行が最小の間隔で 3 本入る高さ。 */
|
|
502
509
|
const API_H_MIN =
|
|
503
510
|
API_ROW_TOP + (API_ROWS - 1) * API_ROW_PITCH_MIN + API_ROW_H + API_ROW_BOTTOM_PAD;
|
|
511
|
+
/** 要求の道と天井看板の字の指定 (#887 で打ち消しの計算に使うため定数へ出した) */
|
|
512
|
+
const API_PATH_SIZE = 12;
|
|
513
|
+
const API_SIGN_SIZE = 14;
|
|
514
|
+
/** 種類の箱の幅と、その中で字が使える幅 (左右 3 ずつ空ける) */
|
|
515
|
+
const API_METHOD_BOX_W = 54;
|
|
516
|
+
const API_METHOD_TEXT_W = 48;
|
|
504
517
|
const API_W_MIN = 200;
|
|
505
518
|
const API_W_MAX = 300;
|
|
506
519
|
|
|
@@ -522,31 +535,48 @@ export function ShapeApiGatewayNode({ node, active, lang }: ShapeProps): JSX.Ele
|
|
|
522
535
|
// 11 のまま入り、長い綴り (日本語の辞書の `DELETE`) だけを縮める。 見積りは等幅と比例の大きい方
|
|
523
536
|
// (`shape-blockchain.tsx` の `字の幅` と同じ考え方で、どちらの書体で描かれても箱からはみ出さない)
|
|
524
537
|
const 種類の字 = (s: string): number =>
|
|
525
|
-
Math.min(11, (11 *
|
|
538
|
+
Math.min(11, (11 * API_METHOD_TEXT_W) / Math.max(displayWidth(s) * 11 * MONO_ADVANCE_RATIO, textWidth(s, 11)));
|
|
526
539
|
const rowPitch = Math.max(
|
|
527
540
|
API_ROW_PITCH_MIN,
|
|
528
541
|
(bh - API_ROW_TOP - API_ROW_H - API_ROW_BOTTOM_PAD) / (API_ROWS - 1),
|
|
529
542
|
);
|
|
530
|
-
const
|
|
543
|
+
const 行ら = [
|
|
544
|
+
{ method: "GET", path: 字引("apiGateway.users"), color: "#27c93f" },
|
|
545
|
+
{ method: "POST", path: 字引("apiGateway.orders"), color: "#e5c07b" },
|
|
546
|
+
{ method: 字引("apiGateway.delete"), path: 字引("apiGateway.session"), color: "#c9302c" },
|
|
547
|
+
];
|
|
548
|
+
/*
|
|
549
|
+
* 打ち消しの上限を出す帯 (#887)。 要求の道の字が使える幅は、行の箱 (bw - 32) から
|
|
550
|
+
* 種類の箱までの 64 と、右端で点滅する印の丸の 16 を除いた残り。
|
|
551
|
+
*
|
|
552
|
+
* **種類の字 (`GET` / `POST`) は打ち消さない**。 `種類の字` が箱の幅 48 に合わせて指定を
|
|
553
|
+
* 決めているので余白が 0 で、打ち消す余地が無い (長い綴りでは上限がちょうど 1.0 になる)。
|
|
554
|
+
* 打ち消しは絵ごとに 1 つの倍率で、最も狭い字が全体を縛る = これを入れると要求の道の字も
|
|
555
|
+
* 戻せなくなる。
|
|
556
|
+
*/
|
|
557
|
+
const 打ち消す字ら: 打ち消す字[] = 行ら.map((e) => ({
|
|
558
|
+
text: e.path,
|
|
559
|
+
size: API_PATH_SIZE,
|
|
560
|
+
帯: { 幅: bw - 32 - 64 - 16, 高さ: API_ROW_H },
|
|
561
|
+
}));
|
|
562
|
+
const 絵 = (倍率: number): JSX.Element => {
|
|
563
|
+
const 倍 = 打ち消しの倍率(倍率, 打ち消す字ら);
|
|
564
|
+
return (
|
|
531
565
|
<g>
|
|
532
566
|
<rect x={x + DROP_SHADOW_D} y={y + DROP_SHADOW_D} width={bw} height={bh} rx={10} fill={frame.stroke} opacity={0.2} stroke="none" />
|
|
533
567
|
<rect data-cdl-role="node-body" x={x} y={y} width={bw} height={bh} rx={10} fill="#1a2332" stroke={frame.stroke} strokeWidth={frame.strokeWidth} />
|
|
534
568
|
<rect x={x} y={y} width={bw} height={36} rx={10} fill="var(--cdl-tone-accent, #2d6a8f)" stroke="none" />
|
|
535
|
-
<text x={cx} y={y + 24} fontSize={
|
|
569
|
+
<text data-cdl-counter-scaled="0" x={cx} y={y + 24} fontSize={API_SIGN_SIZE} fontWeight={700} letterSpacing={3} textAnchor="middle" fill="#ffffff" fontFamily="ui-monospace, SFMono-Regular, Menlo, monospace">
|
|
536
570
|
{字引("apiGateway.sign")}
|
|
537
571
|
</text>
|
|
538
|
-
{
|
|
539
|
-
{ method: "GET", path: 字引("apiGateway.users"), color: "#27c93f" },
|
|
540
|
-
{ method: "POST", path: 字引("apiGateway.orders"), color: "#e5c07b" },
|
|
541
|
-
{ method: 字引("apiGateway.delete"), path: 字引("apiGateway.session"), color: "#c9302c" },
|
|
542
|
-
].map((e, i) => (
|
|
572
|
+
{行ら.map((e, i) => (
|
|
543
573
|
<g key={i} transform={`translate(${x + 16}, ${y + API_ROW_TOP + i * rowPitch})`}>
|
|
544
574
|
<rect x={0} y={0} width={bw - 32} height={API_ROW_H} rx={4} fill="#0f1419" stroke="none" />
|
|
545
|
-
<rect x={0} y={0} width={
|
|
546
|
-
<text x={27} y={16} fontSize={種類の字(e.method)} fontWeight={700} textAnchor="middle" fill="#ffffff" fontFamily="ui-monospace, SFMono-Regular, Menlo, monospace">
|
|
575
|
+
<rect x={0} y={0} width={API_METHOD_BOX_W} height={API_ROW_H} rx={4} fill={e.color} stroke="none" />
|
|
576
|
+
<text data-cdl-counter-scaled="0" x={27} y={16} fontSize={種類の字(e.method)} fontWeight={700} textAnchor="middle" fill="#ffffff" fontFamily="ui-monospace, SFMono-Regular, Menlo, monospace">
|
|
547
577
|
{e.method}
|
|
548
578
|
</text>
|
|
549
|
-
<text x={64} y={16} fontSize={
|
|
579
|
+
<text data-cdl-counter-scaled="1" x={64} y={16} fontSize={API_PATH_SIZE * 倍} fontFamily="ui-monospace, SFMono-Regular, Menlo, monospace" fill="#e6edf3">
|
|
550
580
|
{e.path}
|
|
551
581
|
</text>
|
|
552
582
|
<circle cx={bw - 44} cy={12} r={4} fill="#27c93f" stroke="none">
|
|
@@ -555,7 +585,8 @@ export function ShapeApiGatewayNode({ node, active, lang }: ShapeProps): JSX.Ele
|
|
|
555
585
|
</g>
|
|
556
586
|
))}
|
|
557
587
|
</g>
|
|
558
|
-
|
|
588
|
+
);
|
|
589
|
+
};
|
|
559
590
|
return (
|
|
560
591
|
<g>
|
|
561
592
|
{fitArt(r, 広がり, 絵)}
|