Skip to content

Commit adefba7

Browse files
committed
Add rendered editor cards view (#20)
1 parent 7af6a55 commit adefba7

20 files changed

Lines changed: 620 additions & 2 deletions

src/PrompterOne.Shared/Contracts/UiTestIds.Editor.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,11 @@ public static class Editor
132132
public const string PauseTwoSeconds = "editor-pause-two-seconds";
133133
public const string Profile = "editor-profile";
134134
public const string Redo = "editor-redo";
135+
public const string RenderedEmpty = "editor-rendered-empty";
136+
public const string RenderedFallbackText = "editor-rendered-fallback-text";
137+
public const string RenderedStrip = "editor-rendered-strip";
138+
public const string RenderedTab = "editor-rendered-tab";
139+
public const string RenderedView = "editor-rendered-view";
135140
public const string SourceHighlight = "editor-source-highlight";
136141
public const string SourceInput = "editor-source-input";
137142
public const string SourceGutter = "editor-source-gutter";
@@ -184,6 +189,12 @@ public static class Editor
184189

185190
public static string LocalHistoryRestore(int index) => $"editor-local-history-restore-{index}";
186191

192+
public static string RenderedBlock(int segmentIndex, int blockIndex) => $"editor-rendered-block-{segmentIndex}-{blockIndex}";
193+
194+
public static string RenderedBlockText(int segmentIndex, int blockIndex) => $"editor-rendered-block-text-{segmentIndex}-{blockIndex}";
195+
196+
public static string RenderedSegment(int segmentIndex) => $"editor-rendered-segment-{segmentIndex}";
197+
187198
public static string SplitResultItem(int index) => $"editor-split-result-item-{index}";
188199

189200
public static string SegmentNavigation(int segmentIndex) => $"editor-structure-segment-{segmentIndex}";
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
@namespace PrompterOne.Shared.Components.Editor
2+
3+
<div class="editor-rendered-view" data-test="@UiTestIds.Editor.RenderedView">
4+
<div class="editor-rendered-strip" data-test="@UiTestIds.Editor.RenderedStrip">
5+
@if (Segments.Count == 0)
6+
{
7+
<section class="editor-rendered-card editor-rendered-card--empty" data-test="@UiTestIds.Editor.RenderedEmpty">
8+
<span class="editor-rendered-empty-mark">1</span>
9+
<textarea class="editor-rendered-text editor-rendered-text--empty"
10+
aria-label="@FallbackLabel"
11+
data-test="@UiTestIds.Editor.RenderedFallbackText"
12+
value="@FallbackText"
13+
@oninput="OnFallbackInputAsync"></textarea>
14+
</section>
15+
}
16+
else
17+
{
18+
@foreach (var segment in Segments)
19+
{
20+
<section class="editor-rendered-card" data-test="@UiTestIds.Editor.RenderedSegment(segment.Index)">
21+
<header class="editor-rendered-card-header">
22+
<span class="editor-rendered-number">@segment.Number</span>
23+
<span class="editor-rendered-meta">@segment.TargetWpmLabel</span>
24+
</header>
25+
<div class="editor-rendered-segment-title">@segment.Name</div>
26+
<div class="editor-rendered-segment-detail">
27+
<span>@segment.EmotionLabel</span>
28+
@if (!string.IsNullOrWhiteSpace(segment.DurationLabel))
29+
{
30+
<span>@segment.DurationLabel</span>
31+
}
32+
</div>
33+
34+
@foreach (var block in segment.Blocks)
35+
{
36+
<article class="editor-rendered-block" data-test="@UiTestIds.Editor.RenderedBlock(block.SegmentIndex, block.BlockIndex)">
37+
<div class="editor-rendered-block-head">
38+
<span class="editor-rendered-block-number">@block.Number</span>
39+
<span class="editor-rendered-block-title">@block.Name</span>
40+
</div>
41+
<textarea class="editor-rendered-text"
42+
aria-label="@block.Name"
43+
data-test="@UiTestIds.Editor.RenderedBlockText(block.SegmentIndex, block.BlockIndex)"
44+
value="@block.Text"
45+
@oninput="@((ChangeEventArgs args) => OnBlockInputAsync(block, args))"></textarea>
46+
<div class="editor-rendered-block-meta">
47+
@if (!string.IsNullOrWhiteSpace(block.EmotionLabel))
48+
{
49+
<span>@block.EmotionLabel</span>
50+
}
51+
<span>@block.TargetWpmLabel</span>
52+
</div>
53+
</article>
54+
}
55+
</section>
56+
}
57+
}
58+
</div>
59+
</div>
60+
61+
@code {
62+
[Parameter] public string FallbackText { get; set; } = string.Empty;
63+
64+
[Parameter] public string FallbackLabel { get; set; } = string.Empty;
65+
66+
[Parameter] public IReadOnlyList<EditorRenderedSegmentViewModel> Segments { get; set; } = [];
67+
68+
[Parameter] public EventCallback<EditorRenderedBlockTextChange> TextChanged { get; set; }
69+
70+
private Task OnBlockInputAsync(EditorRenderedBlockViewModel block, ChangeEventArgs args) =>
71+
TextChanged.InvokeAsync(new EditorRenderedBlockTextChange(
72+
block.SegmentIndex,
73+
block.BlockIndex,
74+
args.Value?.ToString() ?? string.Empty));
75+
76+
private Task OnFallbackInputAsync(ChangeEventArgs args) =>
77+
TextChanged.InvokeAsync(new EditorRenderedBlockTextChange(
78+
0,
79+
0,
80+
args.Value?.ToString() ?? string.Empty));
81+
}
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
.editor-rendered-view {
2+
display: flex;
3+
flex: 1 1 auto;
4+
min-width: 0;
5+
min-height: 0;
6+
overflow: hidden;
7+
border: 1px solid rgba(210, 218, 232, .72);
8+
border-radius: 8px;
9+
background: #f6f8fb;
10+
color: #1f2937;
11+
}
12+
13+
.editor-rendered-strip {
14+
display: grid;
15+
grid-auto-columns: minmax(280px, 360px);
16+
grid-auto-flow: column;
17+
min-width: 0;
18+
width: 100%;
19+
overflow-x: auto;
20+
overflow-y: hidden;
21+
scrollbar-color: rgba(72, 82, 104, .32) transparent;
22+
}
23+
24+
.editor-rendered-card {
25+
display: flex;
26+
flex-direction: column;
27+
min-width: 0;
28+
min-height: 100%;
29+
gap: 18px;
30+
padding: 48px 28px 32px;
31+
border-right: 1px solid rgba(210, 218, 232, .84);
32+
background: rgba(255, 255, 255, .92);
33+
}
34+
35+
.editor-rendered-card--empty {
36+
justify-content: flex-start;
37+
}
38+
39+
.editor-rendered-card-header {
40+
display: flex;
41+
align-items: flex-start;
42+
justify-content: space-between;
43+
gap: 12px;
44+
}
45+
46+
.editor-rendered-number,
47+
.editor-rendered-empty-mark {
48+
color: #2f3645;
49+
font-size: 42px;
50+
font-weight: 760;
51+
line-height: .9;
52+
}
53+
54+
.editor-rendered-meta,
55+
.editor-rendered-block-number,
56+
.editor-rendered-block-meta {
57+
color: #7b8494;
58+
font-family: var(--font-mono);
59+
font-size: 11px;
60+
font-weight: 700;
61+
line-height: 1.35;
62+
}
63+
64+
.editor-rendered-segment-title {
65+
color: #222a37;
66+
font-size: 25px;
67+
font-weight: 760;
68+
line-height: 1.16;
69+
overflow-wrap: anywhere;
70+
}
71+
72+
.editor-rendered-segment-detail {
73+
display: flex;
74+
flex-wrap: wrap;
75+
gap: 8px;
76+
min-height: 18px;
77+
color: #9aa3b2;
78+
font-size: 11px;
79+
font-weight: 700;
80+
line-height: 1.35;
81+
text-transform: uppercase;
82+
}
83+
84+
.editor-rendered-block {
85+
display: flex;
86+
flex-direction: column;
87+
gap: 10px;
88+
min-width: 0;
89+
}
90+
91+
.editor-rendered-block-head {
92+
display: flex;
93+
align-items: center;
94+
gap: 9px;
95+
min-width: 0;
96+
}
97+
98+
.editor-rendered-block-title {
99+
min-width: 0;
100+
overflow: hidden;
101+
color: #2f3645;
102+
font-size: 13px;
103+
font-weight: 760;
104+
line-height: 1.25;
105+
text-overflow: ellipsis;
106+
white-space: nowrap;
107+
}
108+
109+
.editor-rendered-text {
110+
width: 100%;
111+
min-height: 150px;
112+
padding: 0;
113+
resize: vertical;
114+
border: 0;
115+
outline: none;
116+
background: transparent;
117+
color: #3b4352;
118+
font: 500 14px/1.55 var(--font-sans);
119+
}
120+
121+
.editor-rendered-text:focus {
122+
box-shadow: inset 3px 0 0 rgba(56, 112, 214, .42);
123+
}
124+
125+
.editor-rendered-text--empty {
126+
min-height: 300px;
127+
}
128+
129+
.editor-rendered-block-meta {
130+
display: flex;
131+
flex-wrap: wrap;
132+
gap: 8px;
133+
}
134+
135+
@media (max-width: 760px) {
136+
.editor-rendered-strip {
137+
grid-auto-columns: minmax(240px, 82vw);
138+
}
139+
140+
.editor-rendered-card {
141+
padding: 34px 22px 26px;
142+
}
143+
}

src/PrompterOne.Shared/Editor/Components/EditorViewModels.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,29 @@ public sealed record EditorLocalRevisionViewModel(
4545
string Title,
4646
string DocumentName);
4747

48+
public sealed record EditorRenderedSegmentViewModel(
49+
int Index,
50+
string Number,
51+
string Name,
52+
string EmotionLabel,
53+
string TargetWpmLabel,
54+
string DurationLabel,
55+
IReadOnlyList<EditorRenderedBlockViewModel> Blocks);
56+
57+
public sealed record EditorRenderedBlockViewModel(
58+
int SegmentIndex,
59+
int BlockIndex,
60+
string Number,
61+
string Name,
62+
string EmotionLabel,
63+
string TargetWpmLabel,
64+
string Text);
65+
66+
public sealed record EditorRenderedBlockTextChange(
67+
int SegmentIndex,
68+
int BlockIndex,
69+
string Text);
70+
4871
public sealed record EditorNavigationTarget(
4972
int SegmentIndex,
5073
int? BlockIndex,

src/PrompterOne.Shared/Editor/Pages/EditorPage.Graph.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ private async Task OnWorkspaceTabChangedAsync(EditorWorkspaceTab tab)
2525
{
2626
_metadataRailSelectedTab = EditorMetadataRailTab.Metadata;
2727
}
28+
29+
if (tab == EditorWorkspaceTab.Rendered)
30+
{
31+
_sourcePanel = null;
32+
}
2833
}
2934

3035
private async Task RebuildScriptGraphAsync(bool force = false)

0 commit comments

Comments
 (0)