@cardenelabs/cdl 0.58.0 → 0.59.1
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 +43 -1
- package/dist/index.cjs +457 -237
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +458 -238
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +413 -193
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +414 -194
- package/dist/react.js.map +1 -1
- package/package.json +1 -1
- package/src/kinds/row-align.ts +30 -0
- package/src/lang.ts +224 -0
- package/src/render/interactive-panel.tsx +202 -126
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { useEffect, useLayoutEffect, useMemo, useState, useSyncExternalStore, useRef } from "react";
|
|
1
|
+
import { createContext, useContext, useEffect, useLayoutEffect, useMemo, useState, useSyncExternalStore, useRef } from "react";
|
|
2
2
|
import type { JSX } from "react";
|
|
3
|
+
import { CDL_TEXT, resolveLang, 字を差し込む, type CdlLang, type CdlTextKey } from "../lang";
|
|
3
4
|
import { assertNever } from "../assert-never";
|
|
4
5
|
import type { CdlDiagram, CdlInput, CdlReadout } from "../types";
|
|
5
6
|
import { createInputSignals, inputDefaultValue } from "../input-signals";
|
|
@@ -15,6 +16,7 @@ import {
|
|
|
15
16
|
import type { Signal, Computed } from "../reactive";
|
|
16
17
|
import { effect } from "../reactive";
|
|
17
18
|
import { textWidth } from "../kinds/text-width";
|
|
19
|
+
import { 桁で割る, 桁で省く } from "../kinds/row-align";
|
|
18
20
|
|
|
19
21
|
/**
|
|
20
22
|
* interactive primitive (input widget / formula / scroll trigger / event handler) を SVG diagram に
|
|
@@ -92,6 +94,55 @@ export type InteractiveSignalsAccessor = {
|
|
|
92
94
|
getBool?: (id: string) => boolean | undefined;
|
|
93
95
|
};
|
|
94
96
|
|
|
97
|
+
/**
|
|
98
|
+
* 操作部の言語 (#849)。 読み出しと入力欄が書く固定の字 (`empty` / `+3 more` / `Todo` など) を引き替える。
|
|
99
|
+
*
|
|
100
|
+
* **React の文脈で届ける**。 読み出しの部品は 100 を超え、すべて `ReadoutWidget` を通して React の木の中で
|
|
101
|
+
* 描かれる。 引数で渡すと全部品の型と呼び出しを書き換えることになり、渡し忘れた部品が英語のまま残る。
|
|
102
|
+
* 形の部品 (#847) が引数で渡すのは、検査が形を関数として直接呼ぶためで、読み出しにはその呼び方が無い。
|
|
103
|
+
*
|
|
104
|
+
* 既定は英語。 文脈の外で描いた部品は変更前と同じ字になる。
|
|
105
|
+
*/
|
|
106
|
+
const 操作部の言語 = createContext<CdlLang>("en");
|
|
107
|
+
|
|
108
|
+
/** 操作部の言語で辞書を引き、`{名前}` に値を差し込む */
|
|
109
|
+
function use字引(): (key: CdlTextKey, values?: Readonly<Record<string, string | number>>) => string {
|
|
110
|
+
const lang = useContext(操作部の言語);
|
|
111
|
+
return (key, values) => (values ? 字を差し込む(CDL_TEXT[lang][key], values) : CDL_TEXT[lang][key]);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* 辞書の字を 1 つ描く。 本文や `<title>` の中に字だけを置く所で使う。
|
|
116
|
+
*
|
|
117
|
+
* 部品ごとに hook を呼ぶ行を足さずに済む (`empty` だけで 44 の部品にある)。 描く markup は字をそのまま
|
|
118
|
+
* 置いた時と同じ。 属性に渡す字と、字を判定に使う所は `use字引` で引く。
|
|
119
|
+
*/
|
|
120
|
+
function 字({ k, v }: { k: CdlTextKey; v?: Readonly<Record<string, string | number>> }): JSX.Element {
|
|
121
|
+
const 引く = use字引();
|
|
122
|
+
return <>{引く(k, v)}</>;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* 辞書の字を SVG の見出し (`<title>`) として描く。
|
|
127
|
+
*
|
|
128
|
+
* **`<title>` の中に `<字>` を置かない**。 React は `<title>` の子を 1 つの文字列として扱い、部品を置くと
|
|
129
|
+
* `[object Object]` と書く (英語の描画の控えとの突き合わせで実測)。 見出しごとこの部品で描き、字は文字列で渡す。
|
|
130
|
+
*
|
|
131
|
+
* `前` は字の前に付ける値 (星の番号 `1: ` など)。 `k` を渡さない時は空の見出しを描く (点いていない灯)。
|
|
132
|
+
*/
|
|
133
|
+
function 字の見出し({
|
|
134
|
+
k,
|
|
135
|
+
v,
|
|
136
|
+
前 = "",
|
|
137
|
+
}: {
|
|
138
|
+
k?: CdlTextKey;
|
|
139
|
+
v?: Readonly<Record<string, string | number>>;
|
|
140
|
+
前?: string;
|
|
141
|
+
}): JSX.Element {
|
|
142
|
+
const 引く = use字引();
|
|
143
|
+
return <title>{k === undefined ? "" : `${前}${引く(k, v)}`}</title>;
|
|
144
|
+
}
|
|
145
|
+
|
|
95
146
|
/**
|
|
96
147
|
* accessor を diagram + signals から構築する SSOT (CAR #255)。
|
|
97
148
|
*
|
|
@@ -593,6 +644,8 @@ export function useInteractiveIntegration(
|
|
|
593
644
|
)
|
|
594
645
|
return null;
|
|
595
646
|
return (
|
|
647
|
+
// 操作部の中の読み出しと入力欄へ、図の言語を届ける (#849)。 型の外の値は英語に落ちる
|
|
648
|
+
<操作部の言語.Provider value={resolveLang(diagram.lang)}>
|
|
596
649
|
<div className="cdl-ip-root" data-cdl-interactive-panel="true">
|
|
597
650
|
{inputs.length > 0 && (
|
|
598
651
|
<div className="cdl-ip-group">
|
|
@@ -628,6 +681,7 @@ export function useInteractiveIntegration(
|
|
|
628
681
|
</div>
|
|
629
682
|
)}
|
|
630
683
|
</div>
|
|
684
|
+
</操作部の言語.Provider>
|
|
631
685
|
);
|
|
632
686
|
}, [diagram, signals, stateOverrides, mergedStateValues]);
|
|
633
687
|
|
|
@@ -2493,7 +2547,7 @@ function SparklineReadout({
|
|
|
2493
2547
|
<div className="cdl-ip-item cdl-ip-readout-sparkline" data-cdl-readout={id}>
|
|
2494
2548
|
<span className="cdl-ip-label">{label}</span>
|
|
2495
2549
|
<div className="cdl-ip-readout-sparkline-empty" style={{ width: w, height: h }}>
|
|
2496
|
-
{points.length === 0 ? "waiting" : "—"}
|
|
2550
|
+
{points.length === 0 ? <字 k="readout.sparkline.waiting" /> : "—"}
|
|
2497
2551
|
</div>
|
|
2498
2552
|
<span className="cdl-ip-readout-sparkline-value">
|
|
2499
2553
|
{Number.isFinite(value) ? value : "—"}
|
|
@@ -2822,12 +2876,14 @@ function TimelineWidget({
|
|
|
2822
2876
|
onClick={cycleSpeed}
|
|
2823
2877
|
aria-label="speed"
|
|
2824
2878
|
>
|
|
2825
|
-
{speed}
|
|
2879
|
+
<字 k="input.timeline.speed" v={{ speed }} />
|
|
2826
2880
|
</button>
|
|
2827
2881
|
</div>
|
|
2828
2882
|
<span className="cdl-ip-timeline-time">
|
|
2829
|
-
|
|
2830
|
-
|
|
2883
|
+
<字
|
|
2884
|
+
k="input.timeline.time"
|
|
2885
|
+
v={{ t: (progress * (input.duration / 1000)).toFixed(1), d: (input.duration / 1000).toFixed(1) }}
|
|
2886
|
+
/>
|
|
2831
2887
|
</span>
|
|
2832
2888
|
</div>
|
|
2833
2889
|
);
|
|
@@ -3129,7 +3185,7 @@ function ArrayBarReadout({
|
|
|
3129
3185
|
<span className="cdl-ip-label">{label}</span>
|
|
3130
3186
|
<div className="cdl-ip-readout-array-bar-row">
|
|
3131
3187
|
{arr.length === 0 ? (
|
|
3132
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
3188
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
3133
3189
|
) : (
|
|
3134
3190
|
arr.map((v, i) => {
|
|
3135
3191
|
const h = Math.max(0, Math.min(1, (v - min) / range));
|
|
@@ -3242,7 +3298,7 @@ function StackedBarReadout({
|
|
|
3242
3298
|
<span className="cdl-ip-label">{label}</span>
|
|
3243
3299
|
<div className="cdl-ip-readout-stacked-bar-row">
|
|
3244
3300
|
{n === 0 ? (
|
|
3245
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
3301
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
3246
3302
|
) : (
|
|
3247
3303
|
Array.from({ length: n }).map((_, i) => {
|
|
3248
3304
|
const va = arrA[i] ?? 0;
|
|
@@ -3378,7 +3434,7 @@ function MatrixReadout({
|
|
|
3378
3434
|
<div className="cdl-ip-item cdl-ip-readout-matrix" data-cdl-readout={id}>
|
|
3379
3435
|
<span className="cdl-ip-label">{label}</span>
|
|
3380
3436
|
{rows === 0 || cols === 0 ? (
|
|
3381
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
3437
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
3382
3438
|
) : (
|
|
3383
3439
|
<svg
|
|
3384
3440
|
className="cdl-ip-readout-matrix-svg"
|
|
@@ -3449,7 +3505,7 @@ function ProgressGroupReadout({
|
|
|
3449
3505
|
<div className="cdl-ip-item cdl-ip-readout-progress-group" data-cdl-readout={id}>
|
|
3450
3506
|
<span className="cdl-ip-label">{label}</span>
|
|
3451
3507
|
{arr.length === 0 ? (
|
|
3452
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
3508
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
3453
3509
|
) : (
|
|
3454
3510
|
<ul className="cdl-ip-readout-progress-group-list">
|
|
3455
3511
|
{arr.map((v, i) => {
|
|
@@ -3539,7 +3595,7 @@ function SequenceTimelineReadout({
|
|
|
3539
3595
|
<div className="cdl-ip-item cdl-ip-readout-sequence-timeline" data-cdl-readout={id}>
|
|
3540
3596
|
<span className="cdl-ip-label">{label}</span>
|
|
3541
3597
|
{events.length === 0 ? (
|
|
3542
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
3598
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
3543
3599
|
) : (
|
|
3544
3600
|
<svg
|
|
3545
3601
|
className="cdl-ip-readout-sequence-timeline-svg"
|
|
@@ -3558,7 +3614,7 @@ function SequenceTimelineReadout({
|
|
|
3558
3614
|
return (
|
|
3559
3615
|
<g key={i} data-cdl-event-marker={e.name}>
|
|
3560
3616
|
<circle cx={x} cy={trackY} r={5} fill={color} stroke="#fff" strokeWidth={1.5}>
|
|
3561
|
-
|
|
3617
|
+
<字の見出し k="readout.sequenceTimeline.title" v={{ name: e.name, t: e.t }} />
|
|
3562
3618
|
</circle>
|
|
3563
3619
|
<text x={x} y={trackY - 12} textAnchor={sequenceLabelAnchor(x, e.name, 10, viewW)} fontSize={10} fill="var(--v4-ink, #1a1f2a)">
|
|
3564
3620
|
{e.name}
|
|
@@ -3624,7 +3680,7 @@ function RadarReadout({
|
|
|
3624
3680
|
<div className="cdl-ip-item cdl-ip-readout-radar" data-cdl-readout={id}>
|
|
3625
3681
|
<span className="cdl-ip-label">{label}</span>
|
|
3626
3682
|
{n === 0 ? (
|
|
3627
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
3683
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
3628
3684
|
) : (
|
|
3629
3685
|
<svg className="cdl-ip-readout-radar-svg" viewBox={`0 0 ${viewW} ${viewH}`} width={viewW} height={viewH}>
|
|
3630
3686
|
{[0.33, 0.66, 1].map((t) => (
|
|
@@ -3716,7 +3772,7 @@ function BubbleChartReadout({
|
|
|
3716
3772
|
<div className="cdl-ip-item cdl-ip-readout-bubble-chart" data-cdl-readout={id}>
|
|
3717
3773
|
<span className="cdl-ip-label">{label}</span>
|
|
3718
3774
|
{bubbles.length === 0 ? (
|
|
3719
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
3775
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
3720
3776
|
) : (
|
|
3721
3777
|
<svg className="cdl-ip-readout-bubble-chart-svg" viewBox={`0 0 ${viewW} ${viewH}`} width={viewW} height={viewH}>
|
|
3722
3778
|
<line x1={pad} x2={viewW - pad} y1={viewH - pad} y2={viewH - pad} stroke="rgba(148,163,184,0.4)" />
|
|
@@ -3727,7 +3783,7 @@ function BubbleChartReadout({
|
|
|
3727
3783
|
const r = 4 + ((Math.max(rMin, Math.min(rMax, b.r)) - rMin) / rRange) * (maxCircleR - 4);
|
|
3728
3784
|
return (
|
|
3729
3785
|
<circle key={i} cx={cx} cy={cy} r={r} fill={color} fillOpacity={0.35} stroke={color} strokeWidth={1.5}>
|
|
3730
|
-
|
|
3786
|
+
<字の見出し k="readout.bubbleChart.title" v={{ x: b.x, y: b.y, r: b.r }} />
|
|
3731
3787
|
</circle>
|
|
3732
3788
|
);
|
|
3733
3789
|
})}
|
|
@@ -3765,7 +3821,7 @@ function DonutReadout({
|
|
|
3765
3821
|
<div className="cdl-ip-item cdl-ip-readout-donut" data-cdl-readout={id}>
|
|
3766
3822
|
<span className="cdl-ip-label">{label}</span>
|
|
3767
3823
|
{arr.length === 0 || total === 0 ? (
|
|
3768
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
3824
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
3769
3825
|
) : (
|
|
3770
3826
|
<svg className="cdl-ip-readout-donut-svg" viewBox={`0 0 ${viewW} ${viewH}`} width={viewW} height={viewH}>
|
|
3771
3827
|
{arr.map((v, i) => {
|
|
@@ -3849,7 +3905,7 @@ function CalendarHeatmapReadout({
|
|
|
3849
3905
|
rx={2}
|
|
3850
3906
|
fill={fill}
|
|
3851
3907
|
>
|
|
3852
|
-
|
|
3908
|
+
<字の見出し k="readout.calendarHeatmap.title" v={{ i, v }} />
|
|
3853
3909
|
</rect>
|
|
3854
3910
|
);
|
|
3855
3911
|
})}
|
|
@@ -4013,7 +4069,7 @@ function CandlestickReadout({
|
|
|
4013
4069
|
<div className="cdl-ip-item cdl-ip-readout-candlestick" data-cdl-readout={id}>
|
|
4014
4070
|
<span className="cdl-ip-label">{label}</span>
|
|
4015
4071
|
{candles.length === 0 ? (
|
|
4016
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
4072
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
4017
4073
|
) : (
|
|
4018
4074
|
<svg className="cdl-ip-readout-candlestick-svg" viewBox={`0 0 ${viewW} ${viewH}`} width={viewW} height={viewH}>
|
|
4019
4075
|
{candles.map((cd, i) => {
|
|
@@ -4037,7 +4093,7 @@ function CandlestickReadout({
|
|
|
4037
4093
|
fill={isUp ? color : color}
|
|
4038
4094
|
fillOpacity={isUp ? 1 : 0.85}
|
|
4039
4095
|
>
|
|
4040
|
-
|
|
4096
|
+
<字の見出し k="readout.candlestick.title" v={{ o: cd.o, h: cd.h, l: cd.l, c: cd.c }} />
|
|
4041
4097
|
</rect>
|
|
4042
4098
|
</g>
|
|
4043
4099
|
);
|
|
@@ -4089,7 +4145,7 @@ function VennReadout({
|
|
|
4089
4145
|
<div className="cdl-ip-item cdl-ip-readout-venn" data-cdl-readout={id}>
|
|
4090
4146
|
<span className="cdl-ip-label">{label}</span>
|
|
4091
4147
|
{sizeA === 0 && sizeB === 0 ? (
|
|
4092
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
4148
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
4093
4149
|
) : (
|
|
4094
4150
|
<svg className="cdl-ip-readout-venn-svg" viewBox={`0 0 ${viewW} ${viewH}`} width={viewW} height={viewH}>
|
|
4095
4151
|
<circle cx={cxA} cy={cy} r={rA} fill={colorA} fillOpacity={0.4} stroke={colorA} strokeWidth={1.5} />
|
|
@@ -4158,13 +4214,13 @@ function SlopeReadout({
|
|
|
4158
4214
|
<div className="cdl-ip-item cdl-ip-readout-slope" data-cdl-readout={id}>
|
|
4159
4215
|
<span className="cdl-ip-label">{label}</span>
|
|
4160
4216
|
{slopes.length === 0 ? (
|
|
4161
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
4217
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
4162
4218
|
) : (
|
|
4163
4219
|
<svg className="cdl-ip-readout-slope-svg" viewBox={`0 0 ${viewW} ${viewH}`} width={viewW} height={viewH}>
|
|
4164
4220
|
<line x1={xL} x2={xL} y1={pad - 4} y2={viewH - pad + 4} stroke="rgba(148,163,184,0.4)" />
|
|
4165
4221
|
<line x1={xR} x2={xR} y1={pad - 4} y2={viewH - pad + 4} stroke="rgba(148,163,184,0.4)" />
|
|
4166
|
-
<text x={xL} y={viewH - 4} fontSize={9} textAnchor="middle" fill="var(--v4-mute, #64748b)"
|
|
4167
|
-
<text x={xR} y={viewH - 4} fontSize={9} textAnchor="middle" fill="var(--v4-mute, #64748b)"
|
|
4222
|
+
<text x={xL} y={viewH - 4} fontSize={9} textAnchor="middle" fill="var(--v4-mute, #64748b)"><字 k="readout.slope.before" /></text>
|
|
4223
|
+
<text x={xR} y={viewH - 4} fontSize={9} textAnchor="middle" fill="var(--v4-mute, #64748b)"><字 k="readout.slope.after" /></text>
|
|
4168
4224
|
{slopes.map((s, i) => {
|
|
4169
4225
|
const yB = yFor(s.before);
|
|
4170
4226
|
const yA = yFor(s.after);
|
|
@@ -4229,7 +4285,7 @@ function FunnelReadout({
|
|
|
4229
4285
|
<div className="cdl-ip-item cdl-ip-readout-funnel" data-cdl-readout={id}>
|
|
4230
4286
|
<span className="cdl-ip-label">{label}</span>
|
|
4231
4287
|
{stages.length === 0 ? (
|
|
4232
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
4288
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
4233
4289
|
) : (
|
|
4234
4290
|
<svg className="cdl-ip-readout-funnel-svg" viewBox={`0 0 ${viewW} ${viewH}`} width={viewW} height={viewH}>
|
|
4235
4291
|
{stages.map((s, i) => {
|
|
@@ -4312,7 +4368,7 @@ function GanttReadout({
|
|
|
4312
4368
|
<div className="cdl-ip-item cdl-ip-readout-gantt" data-cdl-readout={id}>
|
|
4313
4369
|
<span className="cdl-ip-label">{label}</span>
|
|
4314
4370
|
{tasks.length === 0 ? (
|
|
4315
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
4371
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
4316
4372
|
) : (
|
|
4317
4373
|
<svg className="cdl-ip-readout-gantt-svg" viewBox={`0 0 ${viewW} ${viewH}`} width={viewW} height={viewH}>
|
|
4318
4374
|
{tasks.map((t, i) => {
|
|
@@ -4422,7 +4478,7 @@ function TreemapReadout({
|
|
|
4422
4478
|
<div className="cdl-ip-item cdl-ip-readout-treemap" data-cdl-readout={id}>
|
|
4423
4479
|
<span className="cdl-ip-label">{label}</span>
|
|
4424
4480
|
{rects.length === 0 ? (
|
|
4425
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
4481
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
4426
4482
|
) : (
|
|
4427
4483
|
<svg className="cdl-ip-readout-treemap-svg" viewBox={`0 0 ${viewW} ${viewH}`} width={viewW} height={viewH}>
|
|
4428
4484
|
{rects.map((r, i) => (
|
|
@@ -4516,7 +4572,7 @@ function SankeyReadout({
|
|
|
4516
4572
|
<div className="cdl-ip-item cdl-ip-readout-sankey" data-cdl-readout={id}>
|
|
4517
4573
|
<span className="cdl-ip-label">{label}</span>
|
|
4518
4574
|
{flows.length === 0 ? (
|
|
4519
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
4575
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
4520
4576
|
) : (
|
|
4521
4577
|
<svg className="cdl-ip-readout-sankey-svg" viewBox={`0 0 ${viewW} ${viewH}`} width={viewW} height={viewH}>
|
|
4522
4578
|
{/* left bars */}
|
|
@@ -4609,7 +4665,7 @@ function PolarAreaReadout({
|
|
|
4609
4665
|
<div className="cdl-ip-item cdl-ip-readout-polar-area" data-cdl-readout={id}>
|
|
4610
4666
|
<span className="cdl-ip-label">{label}</span>
|
|
4611
4667
|
{n === 0 ? (
|
|
4612
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
4668
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
4613
4669
|
) : (
|
|
4614
4670
|
<svg className="cdl-ip-readout-polar-area-svg" viewBox={`0 0 ${viewW} ${viewH}`} width={viewW} height={viewH}>
|
|
4615
4671
|
{[0.33, 0.66, 1].map((t) => (
|
|
@@ -4679,7 +4735,7 @@ function StepIndicatorReadout({
|
|
|
4679
4735
|
<div className="cdl-ip-item cdl-ip-readout-step-indicator" data-cdl-readout={id}>
|
|
4680
4736
|
<span className="cdl-ip-label">{label}</span>
|
|
4681
4737
|
{n === 0 ? (
|
|
4682
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
4738
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
4683
4739
|
) : (
|
|
4684
4740
|
<svg className="cdl-ip-readout-step-indicator-svg" viewBox={`0 0 ${viewW} ${viewH}`} width={viewW} height={viewH}>
|
|
4685
4741
|
{n > 1
|
|
@@ -4783,10 +4839,10 @@ function BulletChartReadout({
|
|
|
4783
4839
|
<rect x={badX} y={pad} width={avgX - badX} height={trackH} fill="rgba(234,179,8,0.25)" />
|
|
4784
4840
|
<rect x={avgX} y={pad} width={pad + w - avgX} height={trackH} fill="rgba(34,197,94,0.25)" />
|
|
4785
4841
|
<rect x={pad} y={pad + trackH * 0.3} width={actualX - pad} height={trackH * 0.4} fill={colorActual} rx={2}>
|
|
4786
|
-
|
|
4842
|
+
<字の見出し k="readout.bulletChart.actual" v={{ v: safeActual }} />
|
|
4787
4843
|
</rect>
|
|
4788
4844
|
<line x1={targetX} x2={targetX} y1={pad - 2} y2={pad + trackH + 2} stroke="#0f172a" strokeWidth={2}>
|
|
4789
|
-
|
|
4845
|
+
<字の見出し k="readout.bulletChart.target" v={{ v: safeTarget }} />
|
|
4790
4846
|
</line>
|
|
4791
4847
|
</svg>
|
|
4792
4848
|
</div>
|
|
@@ -4865,7 +4921,7 @@ function LeaderboardReadout({
|
|
|
4865
4921
|
<div className="cdl-ip-item cdl-ip-readout-leaderboard" data-cdl-readout={id}>
|
|
4866
4922
|
<span className="cdl-ip-label">{label}</span>
|
|
4867
4923
|
{sorted.length === 0 ? (
|
|
4868
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
4924
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
4869
4925
|
) : (
|
|
4870
4926
|
<ol className="cdl-ip-readout-leaderboard-list">
|
|
4871
4927
|
{sorted.map((it, i) => {
|
|
@@ -4938,7 +4994,8 @@ function TrafficLightReadout({
|
|
|
4938
4994
|
filter: isActive ? `drop-shadow(0 0 6px ${colors[i]})` : undefined,
|
|
4939
4995
|
}}
|
|
4940
4996
|
>
|
|
4941
|
-
|
|
4997
|
+
{/* 灯の見出しだけを辞書で引く。 値は `red` / `yellow` / `amber` / `green` の綴りで読む */}
|
|
4998
|
+
<字の見出し k={isActive ? (["readout.trafficLight.red", "readout.trafficLight.yellow", "readout.trafficLight.green"] as const)[i] : undefined} />
|
|
4942
4999
|
</circle>
|
|
4943
5000
|
);
|
|
4944
5001
|
})}
|
|
@@ -4989,7 +5046,7 @@ function TagCloudReadout({
|
|
|
4989
5046
|
<div className="cdl-ip-item cdl-ip-readout-tag-cloud" data-cdl-readout={id}>
|
|
4990
5047
|
<span className="cdl-ip-label">{label}</span>
|
|
4991
5048
|
{tags.length === 0 ? (
|
|
4992
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
5049
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
4993
5050
|
) : (
|
|
4994
5051
|
<div className="cdl-ip-readout-tag-cloud-list">
|
|
4995
5052
|
{tags.map((t, i) => (
|
|
@@ -5043,7 +5100,7 @@ function ActivityFeedReadout({
|
|
|
5043
5100
|
<div className="cdl-ip-item cdl-ip-readout-activity-feed" data-cdl-readout={id}>
|
|
5044
5101
|
<span className="cdl-ip-label">{label}</span>
|
|
5045
5102
|
{shown.length === 0 ? (
|
|
5046
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
5103
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
5047
5104
|
) : (
|
|
5048
5105
|
<ul className="cdl-ip-readout-activity-feed-list">
|
|
5049
5106
|
{shown.map((e, i) => (
|
|
@@ -5110,9 +5167,9 @@ function RatingReadout({
|
|
|
5110
5167
|
strokeWidth={1}
|
|
5111
5168
|
/>
|
|
5112
5169
|
{isEmpty ? (
|
|
5113
|
-
|
|
5170
|
+
<字の見出し 前={`${i + 1}: `} k="readout.rating.empty" />
|
|
5114
5171
|
) : (
|
|
5115
|
-
|
|
5172
|
+
<字の見出し 前={`${i + 1}: `} k={isFull ? "readout.rating.full" : "readout.rating.half"} />
|
|
5116
5173
|
)}
|
|
5117
5174
|
</svg>
|
|
5118
5175
|
);
|
|
@@ -5239,7 +5296,7 @@ function ChatBubbleReadout({
|
|
|
5239
5296
|
<div className="cdl-ip-item cdl-ip-readout-chat-bubble" data-cdl-readout={id}>
|
|
5240
5297
|
<span className="cdl-ip-label">{label}</span>
|
|
5241
5298
|
{shown.length === 0 ? (
|
|
5242
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
5299
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
5243
5300
|
) : (
|
|
5244
5301
|
<ul className="cdl-ip-readout-chat-bubble-list">
|
|
5245
5302
|
{shown.map((m, i) => (
|
|
@@ -5357,7 +5414,7 @@ function ChecklistReadout({
|
|
|
5357
5414
|
<div className="cdl-ip-item cdl-ip-readout-checklist" data-cdl-readout={id}>
|
|
5358
5415
|
<span className="cdl-ip-label">{label}</span>
|
|
5359
5416
|
{items.length === 0 ? (
|
|
5360
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
5417
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
5361
5418
|
) : (
|
|
5362
5419
|
<>
|
|
5363
5420
|
<div className="cdl-ip-readout-checklist-progress">
|
|
@@ -5494,7 +5551,7 @@ function PriceTagReadout({
|
|
|
5494
5551
|
) : null}
|
|
5495
5552
|
</div>
|
|
5496
5553
|
{savings > 0 ? (
|
|
5497
|
-
<span className="cdl-ip-readout-price-tag-savings"
|
|
5554
|
+
<span className="cdl-ip-readout-price-tag-savings"><字 k="readout.priceTag.save" v={{ amount: `${currency}${savings}` }} /></span>
|
|
5498
5555
|
) : null}
|
|
5499
5556
|
</div>
|
|
5500
5557
|
);
|
|
@@ -5646,6 +5703,13 @@ function StopwatchReadout({
|
|
|
5646
5703
|
);
|
|
5647
5704
|
}
|
|
5648
5705
|
|
|
5706
|
+
/** `confidence-meter` の帯の綴り (`data-cdl-band` の値) から、表示の字の鍵を引く */
|
|
5707
|
+
const 確信度の帯の字 = {
|
|
5708
|
+
low: "readout.confidence.low",
|
|
5709
|
+
mid: "readout.confidence.mid",
|
|
5710
|
+
high: "readout.confidence.high",
|
|
5711
|
+
} as const satisfies Record<string, CdlTextKey>;
|
|
5712
|
+
|
|
5649
5713
|
function ConfidenceMeterReadout({
|
|
5650
5714
|
id,
|
|
5651
5715
|
label,
|
|
@@ -5687,7 +5751,8 @@ function ConfidenceMeterReadout({
|
|
|
5687
5751
|
{Math.round(safeValue)}%
|
|
5688
5752
|
</span>
|
|
5689
5753
|
<span className="cdl-ip-readout-confidence-meter-band" style={{ color: bandColor }}>
|
|
5690
|
-
{
|
|
5754
|
+
{/* 表示の字だけを引く。 `data-cdl-band` は英語の綴りのまま */}
|
|
5755
|
+
<字 k={確信度の帯の字[bandLabel as keyof typeof 確信度の帯の字]} />
|
|
5691
5756
|
</span>
|
|
5692
5757
|
</div>
|
|
5693
5758
|
<svg className="cdl-ip-readout-confidence-meter-svg" viewBox={`0 0 ${viewW} ${viewH}`} width={viewW} height={viewH}>
|
|
@@ -5735,7 +5800,7 @@ function ReactionBarReadout({
|
|
|
5735
5800
|
<div className="cdl-ip-item cdl-ip-readout-reaction-bar" data-cdl-readout={id}>
|
|
5736
5801
|
<span className="cdl-ip-label">{label}</span>
|
|
5737
5802
|
{reactions.length === 0 ? (
|
|
5738
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
5803
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
5739
5804
|
) : (
|
|
5740
5805
|
<div className="cdl-ip-readout-reaction-bar-row">
|
|
5741
5806
|
{reactions.map((r, i) => (
|
|
@@ -5788,7 +5853,7 @@ function PillGroupReadout({
|
|
|
5788
5853
|
<div className="cdl-ip-item cdl-ip-readout-pill-group" data-cdl-readout={id}>
|
|
5789
5854
|
<span className="cdl-ip-label">{label}</span>
|
|
5790
5855
|
{pills.length === 0 ? (
|
|
5791
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
5856
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
5792
5857
|
) : (
|
|
5793
5858
|
<div className="cdl-ip-readout-pill-group-row">
|
|
5794
5859
|
{pills.map((p, i) => (
|
|
@@ -5902,7 +5967,7 @@ function MetricsGridReadout({
|
|
|
5902
5967
|
<div className="cdl-ip-item cdl-ip-readout-metrics-grid" data-cdl-readout={id}>
|
|
5903
5968
|
<span className="cdl-ip-label">{label}</span>
|
|
5904
5969
|
{items.length === 0 ? (
|
|
5905
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
5970
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
5906
5971
|
) : (
|
|
5907
5972
|
<div className="cdl-ip-readout-metrics-grid-grid">
|
|
5908
5973
|
{items.map((m, i) => (
|
|
@@ -6014,7 +6079,7 @@ function IconTileReadout({
|
|
|
6014
6079
|
<div className="cdl-ip-item cdl-ip-readout-icon-tile" data-cdl-readout={id}>
|
|
6015
6080
|
<span className="cdl-ip-label">{label}</span>
|
|
6016
6081
|
{tiles.length === 0 ? (
|
|
6017
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
6082
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
6018
6083
|
) : (
|
|
6019
6084
|
<div className="cdl-ip-readout-icon-tile-row">
|
|
6020
6085
|
{tiles.map((t, i) => (
|
|
@@ -6075,7 +6140,7 @@ function TokenListReadout({
|
|
|
6075
6140
|
<div className="cdl-ip-item cdl-ip-readout-token-list" data-cdl-readout={id}>
|
|
6076
6141
|
<span className="cdl-ip-label">{label}</span>
|
|
6077
6142
|
{tokens.length === 0 ? (
|
|
6078
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
6143
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
6079
6144
|
) : (
|
|
6080
6145
|
<ul className="cdl-ip-readout-token-list-items">
|
|
6081
6146
|
{tokens.map((t, i) => {
|
|
@@ -6149,7 +6214,7 @@ function MapPinReadout({
|
|
|
6149
6214
|
<div className="cdl-ip-item cdl-ip-readout-map-pin" data-cdl-readout={id}>
|
|
6150
6215
|
<span className="cdl-ip-label">{label}</span>
|
|
6151
6216
|
{pins.length === 0 ? (
|
|
6152
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
6217
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
6153
6218
|
) : (
|
|
6154
6219
|
<svg className="cdl-ip-readout-map-pin-svg" viewBox={`0 0 ${viewW} ${viewH}`} width={viewW} height={viewH}>
|
|
6155
6220
|
<rect x={0} y={0} width={viewW} height={viewH} fill="rgba(148,163,184,0.08)" stroke="rgba(148,163,184,0.3)" strokeWidth={1} rx={4} />
|
|
@@ -6194,10 +6259,11 @@ function PriorityBadgeReadout({
|
|
|
6194
6259
|
let level = "med";
|
|
6195
6260
|
if (p === "high" || p === "2") level = "high";
|
|
6196
6261
|
else if (p === "low" || p === "0") level = "low";
|
|
6197
|
-
|
|
6198
|
-
|
|
6199
|
-
|
|
6200
|
-
|
|
6262
|
+
// 値は綴り (`high` / `2` / `low` / `0`) で読み、表示の字だけを辞書で引く (#849)。 `data-cdl-priority` は綴りのまま
|
|
6263
|
+
const spec: Record<string, { icon: string; color: string; bg: string; text: CdlTextKey }> = {
|
|
6264
|
+
high: { icon: "▲", color: "#ef4444", bg: "rgba(239,68,68,0.12)", text: "readout.priority.high" },
|
|
6265
|
+
med: { icon: "●", color: "#eab308", bg: "rgba(234,179,8,0.12)", text: "readout.priority.med" },
|
|
6266
|
+
low: { icon: "▼", color: "#64748b", bg: "rgba(100,116,139,0.12)", text: "readout.priority.low" },
|
|
6201
6267
|
};
|
|
6202
6268
|
const cur = spec[level]!;
|
|
6203
6269
|
return (
|
|
@@ -6209,7 +6275,7 @@ function PriorityBadgeReadout({
|
|
|
6209
6275
|
style={{ background: cur.bg, borderColor: cur.color, color: cur.color }}
|
|
6210
6276
|
>
|
|
6211
6277
|
<span className="cdl-ip-readout-priority-badge-icon">{cur.icon}</span>
|
|
6212
|
-
<span
|
|
6278
|
+
<span><字 k={cur.text} /></span>
|
|
6213
6279
|
</span>
|
|
6214
6280
|
{text ? <span className="cdl-ip-readout-priority-badge-text">{text}</span> : null}
|
|
6215
6281
|
</div>
|
|
@@ -6258,7 +6324,7 @@ function PodiumReadout({
|
|
|
6258
6324
|
<div className="cdl-ip-item cdl-ip-readout-podium" data-cdl-readout={id}>
|
|
6259
6325
|
<span className="cdl-ip-label">{label}</span>
|
|
6260
6326
|
{podium.length === 0 ? (
|
|
6261
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
6327
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
6262
6328
|
) : (
|
|
6263
6329
|
<svg className="cdl-ip-readout-podium-svg" viewBox={`0 0 ${viewW} ${viewH}`} width={viewW} height={viewH}>
|
|
6264
6330
|
{order.map((rankIdx, colIdx) => {
|
|
@@ -6328,7 +6394,7 @@ function PollBarReadout({
|
|
|
6328
6394
|
<div className="cdl-ip-item cdl-ip-readout-poll-bar" data-cdl-readout={id}>
|
|
6329
6395
|
<span className="cdl-ip-label">{label}</span>
|
|
6330
6396
|
{options.length === 0 ? (
|
|
6331
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
6397
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
6332
6398
|
) : (
|
|
6333
6399
|
<ul className="cdl-ip-readout-poll-bar-list">
|
|
6334
6400
|
{options.map((o, i) => {
|
|
@@ -6375,6 +6441,7 @@ function UserStackReadout({
|
|
|
6375
6441
|
max: number;
|
|
6376
6442
|
size: number;
|
|
6377
6443
|
}): JSX.Element {
|
|
6444
|
+
const 引く = use字引();
|
|
6378
6445
|
const names = safeParseArray(value).map(String);
|
|
6379
6446
|
const shown = names.slice(0, max);
|
|
6380
6447
|
const overflow = names.length > max;
|
|
@@ -6391,7 +6458,7 @@ function UserStackReadout({
|
|
|
6391
6458
|
<div className="cdl-ip-item cdl-ip-readout-user-stack" data-cdl-readout={id}>
|
|
6392
6459
|
<span className="cdl-ip-label">{label}</span>
|
|
6393
6460
|
{shown.length === 0 ? (
|
|
6394
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
6461
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
6395
6462
|
) : (
|
|
6396
6463
|
<div className="cdl-ip-readout-user-stack-row">
|
|
6397
6464
|
{shown.map((name, i) => (
|
|
@@ -6420,7 +6487,7 @@ function UserStackReadout({
|
|
|
6420
6487
|
fontSize: `${Math.round(size * 0.35)}px`,
|
|
6421
6488
|
marginLeft: `-${size * 0.3}px`,
|
|
6422
6489
|
}}
|
|
6423
|
-
title={
|
|
6490
|
+
title={引く("readout.more", { n: overflowCount })}
|
|
6424
6491
|
>
|
|
6425
6492
|
+{overflowCount}
|
|
6426
6493
|
</span>
|
|
@@ -6466,7 +6533,7 @@ function CommitListReadout({
|
|
|
6466
6533
|
<div className="cdl-ip-item cdl-ip-readout-commit-list" data-cdl-readout={id}>
|
|
6467
6534
|
<span className="cdl-ip-label">{label}</span>
|
|
6468
6535
|
{shown.length === 0 ? (
|
|
6469
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
6536
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
6470
6537
|
) : (
|
|
6471
6538
|
<ul className="cdl-ip-readout-commit-list-items">
|
|
6472
6539
|
{shown.map((c, i) => (
|
|
@@ -6571,7 +6638,7 @@ function EventLogReadout({
|
|
|
6571
6638
|
<div className="cdl-ip-item cdl-ip-readout-event-log" data-cdl-readout={id}>
|
|
6572
6639
|
<span className="cdl-ip-label">{label}</span>
|
|
6573
6640
|
{shown.length === 0 ? (
|
|
6574
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
6641
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
6575
6642
|
) : (
|
|
6576
6643
|
<ul className="cdl-ip-readout-event-log-items">
|
|
6577
6644
|
{shown.map((e, i) => {
|
|
@@ -6631,7 +6698,7 @@ function SearchResultReadout({
|
|
|
6631
6698
|
<div className="cdl-ip-item cdl-ip-readout-search-result" data-cdl-readout={id}>
|
|
6632
6699
|
<span className="cdl-ip-label">{label}</span>
|
|
6633
6700
|
{shown.length === 0 ? (
|
|
6634
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
6701
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
6635
6702
|
) : (
|
|
6636
6703
|
<ul className="cdl-ip-readout-search-result-items">
|
|
6637
6704
|
{shown.map((h, i) => (
|
|
@@ -6683,7 +6750,7 @@ function RoadmapReadout({
|
|
|
6683
6750
|
<div className="cdl-ip-item cdl-ip-readout-roadmap" data-cdl-readout={id} style={{ minWidth: `${viewW}px` }}>
|
|
6684
6751
|
<span className="cdl-ip-label">{label}</span>
|
|
6685
6752
|
{quarters.length === 0 ? (
|
|
6686
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
6753
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
6687
6754
|
) : (
|
|
6688
6755
|
<div className="cdl-ip-readout-roadmap-row" style={{ minHeight: `${viewH}px` }}>
|
|
6689
6756
|
{quarters.map((q, i) => (
|
|
@@ -6740,7 +6807,7 @@ function WeatherForecastReadout({
|
|
|
6740
6807
|
<div className="cdl-ip-item cdl-ip-readout-weather-forecast" data-cdl-readout={id}>
|
|
6741
6808
|
<span className="cdl-ip-label">{label}</span>
|
|
6742
6809
|
{days.length === 0 ? (
|
|
6743
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
6810
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
6744
6811
|
) : (
|
|
6745
6812
|
<div className="cdl-ip-readout-weather-forecast-row">
|
|
6746
6813
|
{days.map((d, i) => (
|
|
@@ -6796,7 +6863,7 @@ function VideoCardReadout({
|
|
|
6796
6863
|
<div className="cdl-ip-item cdl-ip-readout-video-card" data-cdl-readout={id}>
|
|
6797
6864
|
<span className="cdl-ip-label">{label}</span>
|
|
6798
6865
|
{shown.length === 0 ? (
|
|
6799
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
6866
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
6800
6867
|
) : (
|
|
6801
6868
|
<ul className="cdl-ip-readout-video-card-list">
|
|
6802
6869
|
{shown.map((v, i) => (
|
|
@@ -6807,7 +6874,7 @@ function VideoCardReadout({
|
|
|
6807
6874
|
</div>
|
|
6808
6875
|
<div className="cdl-ip-readout-video-card-info">
|
|
6809
6876
|
<div className="cdl-ip-readout-video-card-title">{v.title}</div>
|
|
6810
|
-
<div className="cdl-ip-readout-video-card-views"
|
|
6877
|
+
<div className="cdl-ip-readout-video-card-views"><字 k="readout.videoCard.views" v={{ v: v.views }} /></div>
|
|
6811
6878
|
</div>
|
|
6812
6879
|
</li>
|
|
6813
6880
|
))}
|
|
@@ -6837,7 +6904,7 @@ function OrderStatusReadout({
|
|
|
6837
6904
|
<div className="cdl-ip-item cdl-ip-readout-order-status" data-cdl-readout={id} data-cdl-step={safeCurrent}>
|
|
6838
6905
|
<span className="cdl-ip-label">{label}</span>
|
|
6839
6906
|
{stepArr.length === 0 ? (
|
|
6840
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
6907
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
6841
6908
|
) : (
|
|
6842
6909
|
<ul className="cdl-ip-readout-order-status-list">
|
|
6843
6910
|
{stepArr.map((s, i) => {
|
|
@@ -6903,12 +6970,12 @@ function AttendanceGridReadout({
|
|
|
6903
6970
|
<div className="cdl-ip-item cdl-ip-readout-attendance-grid" data-cdl-readout={id}>
|
|
6904
6971
|
<span className="cdl-ip-label">{label}</span>
|
|
6905
6972
|
{rows.length === 0 || memberArr.length === 0 ? (
|
|
6906
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
6973
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
6907
6974
|
) : (
|
|
6908
6975
|
<table className="cdl-ip-readout-attendance-grid-table">
|
|
6909
6976
|
<thead>
|
|
6910
6977
|
<tr>
|
|
6911
|
-
<th className="cdl-ip-readout-attendance-grid-corner"
|
|
6978
|
+
<th className="cdl-ip-readout-attendance-grid-corner"><字 k="readout.attendance.corner" /></th>
|
|
6912
6979
|
{memberArr.map((m, i) => (
|
|
6913
6980
|
<th key={i} className="cdl-ip-readout-attendance-grid-member">{m}</th>
|
|
6914
6981
|
))}
|
|
@@ -6978,7 +7045,7 @@ function TimezoneClockReadout({
|
|
|
6978
7045
|
<div className="cdl-ip-item cdl-ip-readout-timezone-clock" data-cdl-readout={id}>
|
|
6979
7046
|
<span className="cdl-ip-label">{label}</span>
|
|
6980
7047
|
{clocks.length === 0 ? (
|
|
6981
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
7048
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
6982
7049
|
) : (
|
|
6983
7050
|
<div className="cdl-ip-readout-timezone-clock-row">
|
|
6984
7051
|
{clocks.map((c, i) => (
|
|
@@ -7027,7 +7094,7 @@ function FormSummaryReadout({
|
|
|
7027
7094
|
<div className="cdl-ip-item cdl-ip-readout-form-summary" data-cdl-readout={id}>
|
|
7028
7095
|
<span className="cdl-ip-label">{label}</span>
|
|
7029
7096
|
{fields.length === 0 ? (
|
|
7030
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
7097
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
7031
7098
|
) : (
|
|
7032
7099
|
<dl className="cdl-ip-readout-form-summary-list">
|
|
7033
7100
|
{fields.map((f, i) => (
|
|
@@ -7079,7 +7146,7 @@ function SongQueueReadout({
|
|
|
7079
7146
|
<div className="cdl-ip-item cdl-ip-readout-song-queue" data-cdl-readout={id} data-cdl-current={safeCurrent}>
|
|
7080
7147
|
<span className="cdl-ip-label">{label}</span>
|
|
7081
7148
|
{shown.length === 0 ? (
|
|
7082
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
7149
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
7083
7150
|
) : (
|
|
7084
7151
|
<ol className="cdl-ip-readout-song-queue-list">
|
|
7085
7152
|
{shown.map((s, i) => {
|
|
@@ -7142,12 +7209,20 @@ function CalendarMonthReadout({
|
|
|
7142
7209
|
}
|
|
7143
7210
|
}
|
|
7144
7211
|
// build 6 x 7 grid (day of month の初日 offset は infer せず、 単純に days[i].day を敷き詰め)
|
|
7145
|
-
const weekDays = [
|
|
7212
|
+
const weekDays = [
|
|
7213
|
+
"readout.weekday.0",
|
|
7214
|
+
"readout.weekday.1",
|
|
7215
|
+
"readout.weekday.2",
|
|
7216
|
+
"readout.weekday.3",
|
|
7217
|
+
"readout.weekday.4",
|
|
7218
|
+
"readout.weekday.5",
|
|
7219
|
+
"readout.weekday.6",
|
|
7220
|
+
] as const;
|
|
7146
7221
|
return (
|
|
7147
7222
|
<div className="cdl-ip-item cdl-ip-readout-calendar-month" data-cdl-readout={id}>
|
|
7148
7223
|
<span className="cdl-ip-label">{label}</span>
|
|
7149
7224
|
{days.length === 0 ? (
|
|
7150
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
7225
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
7151
7226
|
) : (
|
|
7152
7227
|
<div className="cdl-ip-readout-calendar-month-widget">
|
|
7153
7228
|
{monthName ? (
|
|
@@ -7155,7 +7230,7 @@ function CalendarMonthReadout({
|
|
|
7155
7230
|
) : null}
|
|
7156
7231
|
<div className="cdl-ip-readout-calendar-month-weekdays">
|
|
7157
7232
|
{weekDays.map((w) => (
|
|
7158
|
-
<span key={w} className="cdl-ip-readout-calendar-month-weekday"
|
|
7233
|
+
<span key={w} className="cdl-ip-readout-calendar-month-weekday"><字 k={w} /></span>
|
|
7159
7234
|
))}
|
|
7160
7235
|
</div>
|
|
7161
7236
|
<div className="cdl-ip-readout-calendar-month-grid">
|
|
@@ -7213,7 +7288,7 @@ function TerminalReadout({
|
|
|
7213
7288
|
<div className="cdl-ip-item cdl-ip-readout-terminal" data-cdl-readout={id}>
|
|
7214
7289
|
<span className="cdl-ip-label">{label}</span>
|
|
7215
7290
|
{shown.length === 0 ? (
|
|
7216
|
-
<span className="cdl-ip-readout-array-bar-empty"
|
|
7291
|
+
<span className="cdl-ip-readout-array-bar-empty"><字 k="readout.empty" /></span>
|
|
7217
7292
|
) : (
|
|
7218
7293
|
<div className="cdl-ip-readout-terminal-window">
|
|
7219
7294
|
<div className="cdl-ip-readout-terminal-titlebar">
|
|
@@ -7333,15 +7408,12 @@ function KanbanBoardReadout({
|
|
|
7333
7408
|
max: number;
|
|
7334
7409
|
}): JSX.Element {
|
|
7335
7410
|
type Task = { title: string; priority?: string };
|
|
7336
|
-
const
|
|
7337
|
-
|
|
7338
|
-
inprogress: { key: "inprogress", label: "In Progress", color: "#2563eb", tasks: [] },
|
|
7339
|
-
done: { key: "done", label: "Done", color: "#22c55e", tasks: [] },
|
|
7340
|
-
} as unknown as { key: string; label: string; color: string; tasks: Task[] };
|
|
7411
|
+
const 引く = use字引();
|
|
7412
|
+
// 列は綴り (`todo` / `inprogress` / `done`) で振り分け、見出しの字だけを辞書で引く (#849)
|
|
7341
7413
|
const buckets: Record<string, { key: string; label: string; color: string; tasks: Task[] }> = {
|
|
7342
|
-
todo: { key: "todo", label: "
|
|
7343
|
-
inprogress: { key: "inprogress", label: "
|
|
7344
|
-
done: { key: "done", label: "
|
|
7414
|
+
todo: { key: "todo", label: 引く("readout.kanban.todo"), color: "#94a3b8", tasks: [] },
|
|
7415
|
+
inprogress: { key: "inprogress", label: 引く("readout.kanban.inprogress"), color: "#2563eb", tasks: [] },
|
|
7416
|
+
done: { key: "done", label: 引く("readout.kanban.done"), color: "#22c55e", tasks: [] },
|
|
7345
7417
|
};
|
|
7346
7418
|
const trimmed = value.trim();
|
|
7347
7419
|
if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
|
|
@@ -7362,7 +7434,6 @@ function KanbanBoardReadout({
|
|
|
7362
7434
|
// silent skip
|
|
7363
7435
|
}
|
|
7364
7436
|
}
|
|
7365
|
-
void columns;
|
|
7366
7437
|
const order = ["todo", "inprogress", "done"] as const;
|
|
7367
7438
|
const rowH = 26;
|
|
7368
7439
|
const headerH = 28;
|
|
@@ -7440,7 +7511,7 @@ function KanbanBoardReadout({
|
|
|
7440
7511
|
style={{ userSelect: "none" }}
|
|
7441
7512
|
>
|
|
7442
7513
|
<title>{task.title}</title>
|
|
7443
|
-
{task.title
|
|
7514
|
+
{桁で省く(task.title, 18)}
|
|
7444
7515
|
</text>
|
|
7445
7516
|
</g>
|
|
7446
7517
|
);
|
|
@@ -7454,7 +7525,7 @@ function KanbanBoardReadout({
|
|
|
7454
7525
|
fill="#64748b"
|
|
7455
7526
|
style={{ userSelect: "none" }}
|
|
7456
7527
|
>
|
|
7457
|
-
|
|
7528
|
+
<字 k="readout.more" v={{ n: overflow }} />
|
|
7458
7529
|
</text>
|
|
7459
7530
|
) : null}
|
|
7460
7531
|
</g>
|
|
@@ -7597,7 +7668,7 @@ function TimelineVerticalReadout({
|
|
|
7597
7668
|
style={{ userSelect: "none" }}
|
|
7598
7669
|
>
|
|
7599
7670
|
<title>{ev.title}</title>
|
|
7600
|
-
{ev.title
|
|
7671
|
+
{桁で省く(ev.title, 38)}
|
|
7601
7672
|
</text>
|
|
7602
7673
|
{ev.description ? (
|
|
7603
7674
|
<text
|
|
@@ -7608,7 +7679,7 @@ function TimelineVerticalReadout({
|
|
|
7608
7679
|
style={{ userSelect: "none" }}
|
|
7609
7680
|
>
|
|
7610
7681
|
<title>{ev.description}</title>
|
|
7611
|
-
{ev.description
|
|
7682
|
+
{桁で省く(ev.description, 44)}
|
|
7612
7683
|
</text>
|
|
7613
7684
|
) : null}
|
|
7614
7685
|
</g>
|
|
@@ -7966,7 +8037,7 @@ function StepProgressReadout({
|
|
|
7966
8037
|
style={{ userSelect: "none" }}
|
|
7967
8038
|
>
|
|
7968
8039
|
<title>{s}</title>
|
|
7969
|
-
{s
|
|
8040
|
+
{桁で省く(s, 10)}
|
|
7970
8041
|
</text>
|
|
7971
8042
|
</g>
|
|
7972
8043
|
);
|
|
@@ -8032,7 +8103,7 @@ function UserPresenceReadout({
|
|
|
8032
8103
|
fill="#0f172a"
|
|
8033
8104
|
style={{ userSelect: "none" }}
|
|
8034
8105
|
>
|
|
8035
|
-
{u.name
|
|
8106
|
+
{桁で省く(u.name, 24)}
|
|
8036
8107
|
</text>
|
|
8037
8108
|
<text
|
|
8038
8109
|
x={width - 4}
|
|
@@ -8056,7 +8127,7 @@ function UserPresenceReadout({
|
|
|
8056
8127
|
fill="#64748b"
|
|
8057
8128
|
style={{ userSelect: "none" }}
|
|
8058
8129
|
>
|
|
8059
|
-
|
|
8130
|
+
<字 k="readout.more" v={{ n: overflow }} />
|
|
8060
8131
|
</text>
|
|
8061
8132
|
) : null}
|
|
8062
8133
|
</svg>
|
|
@@ -8113,7 +8184,7 @@ function RatingThumbReadout({
|
|
|
8113
8184
|
▲ {upCount}
|
|
8114
8185
|
</text>
|
|
8115
8186
|
<text x={width / 2} y={20} fontSize={11} textAnchor="middle" fill="#64748b" style={{ userSelect: "none" }}>
|
|
8116
|
-
{
|
|
8187
|
+
<字 k="readout.ratingThumb.summary" v={{ pct: upPct, total }} />
|
|
8117
8188
|
</text>
|
|
8118
8189
|
<text
|
|
8119
8190
|
x={width - 8}
|
|
@@ -8202,7 +8273,7 @@ function OrgChartMiniReadout({
|
|
|
8202
8273
|
style={{ userSelect: "none" }}
|
|
8203
8274
|
>
|
|
8204
8275
|
<title>{n.name}</title>
|
|
8205
|
-
{n.name
|
|
8276
|
+
{桁で省く(n.name, 10)}
|
|
8206
8277
|
</text>
|
|
8207
8278
|
{lvl < 2 && byLevel[lvl + 1]!.length > 0 ? (
|
|
8208
8279
|
<line
|
|
@@ -8300,8 +8371,7 @@ function KpiTrendTileReadout({
|
|
|
8300
8371
|
{unit} ({deltaPct.toFixed(1)}%)
|
|
8301
8372
|
</text>
|
|
8302
8373
|
<text x={12} y={78} fontSize={10} fill="#64748b" style={{ userSelect: "none" }}>
|
|
8303
|
-
prev {prev}
|
|
8304
|
-
{unit}
|
|
8374
|
+
<字 k="readout.kpiTrend.prev" v={{ v: `${prev}${unit}` }} />
|
|
8305
8375
|
</text>
|
|
8306
8376
|
{history.length > 1 ? (
|
|
8307
8377
|
<polyline points={points} fill="none" stroke={arrowColor} strokeWidth={2} />
|
|
@@ -8401,7 +8471,7 @@ function QuickPollEmojiReadout({
|
|
|
8401
8471
|
fill="#64748b"
|
|
8402
8472
|
style={{ userSelect: "none" }}
|
|
8403
8473
|
>
|
|
8404
|
-
total {total}
|
|
8474
|
+
<字 k="readout.poll.total" v={{ n: total }} />
|
|
8405
8475
|
</text>
|
|
8406
8476
|
</svg>
|
|
8407
8477
|
</div>
|
|
@@ -8544,10 +8614,10 @@ function ThreadSummaryReadout({
|
|
|
8544
8614
|
>
|
|
8545
8615
|
<rect x={0} y={0} width={width} height={height} fill="#f8fafc" rx={6} />
|
|
8546
8616
|
<text x={12} y={22} fontSize={12} fontWeight={600} fill="#0f172a" style={{ userSelect: "none" }}>
|
|
8547
|
-
{participants}
|
|
8617
|
+
<字 k="readout.thread.participants" v={{ n: participants }} />
|
|
8548
8618
|
</text>
|
|
8549
8619
|
<text x={12} y={42} fontSize={11} fill="#334155" style={{ userSelect: "none" }}>
|
|
8550
|
-
last:
|
|
8620
|
+
<字 k="readout.thread.last" v={{ name: lastAuthor }} />
|
|
8551
8621
|
</text>
|
|
8552
8622
|
<text x={12} y={60} fontSize={10} fill="#64748b" style={{ userSelect: "none" }}>
|
|
8553
8623
|
{timeAgo}
|
|
@@ -8587,7 +8657,7 @@ function ReadReceiptReadout({
|
|
|
8587
8657
|
colorPending: string;
|
|
8588
8658
|
}): JSX.Element {
|
|
8589
8659
|
const status = Number.isFinite(value) ? Math.max(0, Math.min(2, Math.floor(value))) : 0;
|
|
8590
|
-
const
|
|
8660
|
+
const labelKey = status === 0 ? "readout.readReceipt.sent" : status === 1 ? "readout.readReceipt.delivered" : "readout.readReceipt.read";
|
|
8591
8661
|
const iconColor = status === 2 ? colorRead : colorPending;
|
|
8592
8662
|
const width = 180;
|
|
8593
8663
|
const height = 32;
|
|
@@ -8618,7 +8688,7 @@ function ReadReceiptReadout({
|
|
|
8618
8688
|
) : null}
|
|
8619
8689
|
</g>
|
|
8620
8690
|
<text x={52} y={height / 2 + 4} fontSize={11} fontWeight={600} fill={iconColor} style={{ userSelect: "none" }}>
|
|
8621
|
-
{
|
|
8691
|
+
<字 k={labelKey} />
|
|
8622
8692
|
</text>
|
|
8623
8693
|
</svg>
|
|
8624
8694
|
</div>
|
|
@@ -8639,7 +8709,7 @@ function PasswordStrengthReadout({
|
|
|
8639
8709
|
colorWeak: string;
|
|
8640
8710
|
}): JSX.Element {
|
|
8641
8711
|
const level = Number.isFinite(value) ? Math.max(0, Math.min(4, Math.floor(value))) : 0;
|
|
8642
|
-
const labels = ["
|
|
8712
|
+
const labels = ["readout.password.0", "readout.password.1", "readout.password.2", "readout.password.3", "readout.password.4"] as const;
|
|
8643
8713
|
const colors = [colorWeak, "#f97316", "#eab308", "#84cc16", colorStrong];
|
|
8644
8714
|
const barW = 46;
|
|
8645
8715
|
const gap = 6;
|
|
@@ -8680,7 +8750,7 @@ function PasswordStrengthReadout({
|
|
|
8680
8750
|
fill={level > 0 ? colors[level] ?? colorStrong : "#94a3b8"}
|
|
8681
8751
|
style={{ userSelect: "none" }}
|
|
8682
8752
|
>
|
|
8683
|
-
{labels[level]}
|
|
8753
|
+
<字 k={labels[level]!} />
|
|
8684
8754
|
</text>
|
|
8685
8755
|
</svg>
|
|
8686
8756
|
</div>
|
|
@@ -8818,10 +8888,10 @@ function FileDropzoneReadout({
|
|
|
8818
8888
|
</text>
|
|
8819
8889
|
<text x={54} y={34} fontSize={12} fontWeight={600} fill="#0f172a" style={{ userSelect: "none" }}>
|
|
8820
8890
|
<title>{filename}</title>
|
|
8821
|
-
{filename
|
|
8891
|
+
{桁で省く(filename, 26)}
|
|
8822
8892
|
</text>
|
|
8823
8893
|
<text x={54} y={50} fontSize={10} fill="#64748b" style={{ userSelect: "none" }}>
|
|
8824
|
-
uploaded
|
|
8894
|
+
<字 k="readout.dropzone.uploaded" />
|
|
8825
8895
|
</text>
|
|
8826
8896
|
</g>
|
|
8827
8897
|
) : (
|
|
@@ -8835,7 +8905,7 @@ function FileDropzoneReadout({
|
|
|
8835
8905
|
fill="#64748b"
|
|
8836
8906
|
style={{ userSelect: "none" }}
|
|
8837
8907
|
>
|
|
8838
|
-
|
|
8908
|
+
<字 k="readout.dropzone.drop" />
|
|
8839
8909
|
</text>
|
|
8840
8910
|
<text
|
|
8841
8911
|
x={width / 2}
|
|
@@ -8845,7 +8915,7 @@ function FileDropzoneReadout({
|
|
|
8845
8915
|
fill="#94a3b8"
|
|
8846
8916
|
style={{ userSelect: "none" }}
|
|
8847
8917
|
>
|
|
8848
|
-
|
|
8918
|
+
<字 k="readout.dropzone.browse" />
|
|
8849
8919
|
</text>
|
|
8850
8920
|
</g>
|
|
8851
8921
|
)}
|
|
@@ -8886,7 +8956,7 @@ function LogStreamReadout({
|
|
|
8886
8956
|
}
|
|
8887
8957
|
}
|
|
8888
8958
|
const shown = rows.slice(-5);
|
|
8889
|
-
const levelLabels = ["
|
|
8959
|
+
const levelLabels = ["readout.log.0", "readout.log.1", "readout.log.2", "readout.log.3"] as const;
|
|
8890
8960
|
const levelColors = ["#94a3b8", "#2563eb", "#f97316", "#ef4444"];
|
|
8891
8961
|
const width = 300;
|
|
8892
8962
|
const rowH = 18;
|
|
@@ -8903,7 +8973,7 @@ function LogStreamReadout({
|
|
|
8903
8973
|
<rect x={0} y={0} width={width} height={height} fill="#0f172a" rx={4} />
|
|
8904
8974
|
{shown.map((r, i) => {
|
|
8905
8975
|
const y = 4 + i * rowH;
|
|
8906
|
-
const displayMsg = r.msg
|
|
8976
|
+
const displayMsg = 桁で省く(r.msg, 24);
|
|
8907
8977
|
return (
|
|
8908
8978
|
<g key={i} data-cdl-log-row={i}>
|
|
8909
8979
|
<text x={6} y={y + 12} fontSize={9} fill="#94a3b8" fontFamily="monospace" style={{ userSelect: "none" }}>
|
|
@@ -8920,7 +8990,7 @@ function LogStreamReadout({
|
|
|
8920
8990
|
fontFamily="monospace"
|
|
8921
8991
|
style={{ userSelect: "none" }}
|
|
8922
8992
|
>
|
|
8923
|
-
{levelLabels[r.level] ?? "
|
|
8993
|
+
<字 k={levelLabels[r.level] ?? "readout.log.1"} />
|
|
8924
8994
|
</text>
|
|
8925
8995
|
<text x={94} y={y + 12} fontSize={10} fill="#e2e8f0" fontFamily="monospace" style={{ userSelect: "none" }}>
|
|
8926
8996
|
<title>{r.msg}</title>
|
|
@@ -9002,7 +9072,7 @@ function AlertBannerReadout({
|
|
|
9002
9072
|
style={{ userSelect: "none" }}
|
|
9003
9073
|
>
|
|
9004
9074
|
<title>{message}</title>
|
|
9005
|
-
{message
|
|
9075
|
+
{桁で省く(message, 32)}
|
|
9006
9076
|
</text>
|
|
9007
9077
|
</svg>
|
|
9008
9078
|
</div>
|
|
@@ -9075,7 +9145,7 @@ function ServiceHealthReadout({
|
|
|
9075
9145
|
style={{ userSelect: "none" }}
|
|
9076
9146
|
>
|
|
9077
9147
|
<title>{s.name}</title>
|
|
9078
|
-
{s.name
|
|
9148
|
+
{桁で省く(s.name, 10)}
|
|
9079
9149
|
</text>
|
|
9080
9150
|
</g>
|
|
9081
9151
|
);
|
|
@@ -9120,11 +9190,11 @@ function CartSummaryReadout({
|
|
|
9120
9190
|
if (!Number.isFinite(subtotal)) subtotal = 0;
|
|
9121
9191
|
if (!Number.isFinite(shipping)) shipping = 0;
|
|
9122
9192
|
if (!Number.isFinite(total)) total = 0;
|
|
9123
|
-
const rows = [
|
|
9124
|
-
{ l: "
|
|
9125
|
-
{ l: "
|
|
9126
|
-
{ l: "
|
|
9127
|
-
{ l: "
|
|
9193
|
+
const rows: { l: CdlTextKey; v: string; bold: boolean }[] = [
|
|
9194
|
+
{ l: "readout.cart.items", v: `${items}`, bold: false },
|
|
9195
|
+
{ l: "readout.cart.subtotal", v: `${currency}${subtotal.toFixed(2)}`, bold: false },
|
|
9196
|
+
{ l: "readout.cart.shipping", v: `${currency}${shipping.toFixed(2)}`, bold: false },
|
|
9197
|
+
{ l: "readout.cart.total", v: `${currency}${total.toFixed(2)}`, bold: true },
|
|
9128
9198
|
];
|
|
9129
9199
|
const width = 260;
|
|
9130
9200
|
const rowH = 20;
|
|
@@ -9155,7 +9225,7 @@ function CartSummaryReadout({
|
|
|
9155
9225
|
fill={isTotal ? colorTotal : "#334155"}
|
|
9156
9226
|
style={{ userSelect: "none" }}
|
|
9157
9227
|
>
|
|
9158
|
-
{r.l}
|
|
9228
|
+
<字 k={r.l} />
|
|
9159
9229
|
</text>
|
|
9160
9230
|
<text
|
|
9161
9231
|
x={width - 12}
|
|
@@ -9208,6 +9278,9 @@ function PricingTierReadout({
|
|
|
9208
9278
|
}
|
|
9209
9279
|
}
|
|
9210
9280
|
if (!Number.isFinite(price)) price = 0;
|
|
9281
|
+
const 引く = use字引();
|
|
9282
|
+
// 名前が空の時の既定の名前。 見出しと押す札の 2 か所で使う
|
|
9283
|
+
const 見せる名前 = planName || 引く("readout.pricing.plan");
|
|
9211
9284
|
const width = 240;
|
|
9212
9285
|
const height = 176;
|
|
9213
9286
|
return (
|
|
@@ -9230,7 +9303,7 @@ function PricingTierReadout({
|
|
|
9230
9303
|
fill="#ffffff"
|
|
9231
9304
|
style={{ userSelect: "none" }}
|
|
9232
9305
|
>
|
|
9233
|
-
{
|
|
9306
|
+
{見せる名前}
|
|
9234
9307
|
</text>
|
|
9235
9308
|
<text
|
|
9236
9309
|
x={width / 2}
|
|
@@ -9252,11 +9325,11 @@ function PricingTierReadout({
|
|
|
9252
9325
|
fill="#64748b"
|
|
9253
9326
|
style={{ userSelect: "none" }}
|
|
9254
9327
|
>
|
|
9255
|
-
|
|
9328
|
+
<字 k="readout.pricing.perMonth" />
|
|
9256
9329
|
</text>
|
|
9257
9330
|
{features.slice(0, 3).map((f, i) => {
|
|
9258
9331
|
const y = 96 + i * 18;
|
|
9259
|
-
const displayF = f
|
|
9332
|
+
const displayF = 桁で省く(f, 24);
|
|
9260
9333
|
return (
|
|
9261
9334
|
<g key={i} data-cdl-tier-feature={i}>
|
|
9262
9335
|
<text x={16} y={y} fontSize={11} fill={colorAccent} style={{ userSelect: "none" }}>
|
|
@@ -9279,7 +9352,7 @@ function PricingTierReadout({
|
|
|
9279
9352
|
fill="#ffffff"
|
|
9280
9353
|
style={{ userSelect: "none" }}
|
|
9281
9354
|
>
|
|
9282
|
-
|
|
9355
|
+
{引く("readout.pricing.get", { name: 見せる名前 })}
|
|
9283
9356
|
</text>
|
|
9284
9357
|
</svg>
|
|
9285
9358
|
</div>
|
|
@@ -9345,7 +9418,7 @@ function CouponCodeReadout({
|
|
|
9345
9418
|
fontFamily="monospace"
|
|
9346
9419
|
style={{ userSelect: "none" }}
|
|
9347
9420
|
>
|
|
9348
|
-
{code || "
|
|
9421
|
+
{code || <字 k="readout.coupon.placeholder" />}
|
|
9349
9422
|
</text>
|
|
9350
9423
|
{applied ? (
|
|
9351
9424
|
<g data-cdl-coupon-applied="1">
|
|
@@ -9359,7 +9432,7 @@ function CouponCodeReadout({
|
|
|
9359
9432
|
fill="#ffffff"
|
|
9360
9433
|
style={{ userSelect: "none" }}
|
|
9361
9434
|
>
|
|
9362
|
-
|
|
9435
|
+
<字 k="readout.coupon.off" v={{ pct: discountPct }} />
|
|
9363
9436
|
</text>
|
|
9364
9437
|
</g>
|
|
9365
9438
|
) : (
|
|
@@ -9374,7 +9447,7 @@ function CouponCodeReadout({
|
|
|
9374
9447
|
fill="#ffffff"
|
|
9375
9448
|
style={{ userSelect: "none" }}
|
|
9376
9449
|
>
|
|
9377
|
-
|
|
9450
|
+
<字 k="readout.coupon.apply" />
|
|
9378
9451
|
</text>
|
|
9379
9452
|
</g>
|
|
9380
9453
|
)}
|
|
@@ -9415,6 +9488,9 @@ function ArticlePreviewReadout({
|
|
|
9415
9488
|
const width = 300;
|
|
9416
9489
|
const height = 116;
|
|
9417
9490
|
const thumbW = 80;
|
|
9491
|
+
// 抜粋は 1 行 28 桁で 2 行に割る (#851)。 1 行目は収まるだけ置いて `…` を付けず、残りを 2 行目に続ける。
|
|
9492
|
+
// 以前は 1 行目を 27 字と `…` で切り、2 行目を 29 字目から描いていたので、28 字目がどちらの行にも出なかった
|
|
9493
|
+
const [抜粋の一行目, 抜粋の残り] = 桁で割る(excerpt, 28);
|
|
9418
9494
|
return (
|
|
9419
9495
|
<div className="cdl-ip-item cdl-ip-readout-article-preview" data-cdl-readout={id}>
|
|
9420
9496
|
<span className="cdl-ip-label">{label}</span>
|
|
@@ -9446,17 +9522,17 @@ function ArticlePreviewReadout({
|
|
|
9446
9522
|
style={{ userSelect: "none" }}
|
|
9447
9523
|
>
|
|
9448
9524
|
<title>{title}</title>
|
|
9449
|
-
{title
|
|
9525
|
+
{桁で省く(title, 26)}
|
|
9450
9526
|
</text>
|
|
9451
9527
|
<text x={thumbW + 20} y={44} fontSize={10} fill="#334155" style={{ userSelect: "none" }}>
|
|
9452
9528
|
<title>{excerpt}</title>
|
|
9453
|
-
{
|
|
9529
|
+
{抜粋の一行目}
|
|
9454
9530
|
</text>
|
|
9455
9531
|
<text x={thumbW + 20} y={60} fontSize={10} fill="#334155" style={{ userSelect: "none" }}>
|
|
9456
|
-
{
|
|
9532
|
+
{桁で省く(抜粋の残り, 28)}
|
|
9457
9533
|
</text>
|
|
9458
9534
|
<text x={thumbW + 20} y={height - 14} fontSize={10} fontWeight={600} fill="#64748b" style={{ userSelect: "none" }}>
|
|
9459
|
-
by {author}
|
|
9535
|
+
<字 k="readout.article.by" v={{ author }} />
|
|
9460
9536
|
</text>
|
|
9461
9537
|
<text x={width - 8} y={height - 14} fontSize={10} textAnchor="end" fill="#94a3b8" style={{ userSelect: "none" }}>
|
|
9462
9538
|
{timeAgo}
|
|
@@ -9516,7 +9592,7 @@ function TocNavReadout({
|
|
|
9516
9592
|
{shown.map((it, i) => {
|
|
9517
9593
|
const y = 4 + i * rowH;
|
|
9518
9594
|
const indent = 12 + it.level * 16;
|
|
9519
|
-
const displayT = it.title
|
|
9595
|
+
const displayT = 桁で省く(it.title, 30);
|
|
9520
9596
|
return (
|
|
9521
9597
|
<g key={i} data-cdl-toc-item={i}>
|
|
9522
9598
|
{it.active ? (
|