Skip to content

Commit 4d0c271

Browse files
committed
feat(patch-detail): upgrade the patch-comment form to the new version
Did it very hastily and the two components aren't in sync because when I applied the DetailActivity cmp changes (latest, evolved from 100% working Title&Desc cmp) to Title&Desc cmp it regressed (text-areas were full-width in editing even if the text is narrow) Signed-off-by: Konstantinos Maninakis <[email protected]>
1 parent 74f5737 commit 4d0c271

File tree

3 files changed

+116
-41
lines changed

3 files changed

+116
-41
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
- also acts as a safe "spacer" between the two aforementioned buttons protecting against misclicks that would otherwise come with a big penalty
2727
- add a new button to toggle a markdown preview of the current changes before submitting
2828
- also triggerable with keyboard shortcut `Alt + P`
29+
- after toggling to markdown preview and back to editing the undo/redo history (Ctrl/Cmd + Z and Ctrl/Cmd + Shift + Z) is still available. Even if the form contains multiple controls (e.g. two text-areas) then the undo/redo history spanning _all of them in the order they were changed_ is still retained
2930
- polish text-field sizing dynamics:
3031
- use 1 line of text as starting height when empty for the patch title field and 4 lines for the patch description
3132
- respectively limit the max vertical lines for the former and the latter

src/webviews/src/components/PatchDetailActivity.vue

Lines changed: 114 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -79,42 +79,37 @@ const patchEvents = computed(() =>
7979
const formRef = useTemplateRef<HTMLElement>('formRef')
8080
const commentTextAreaRef = useTemplateRef<HTMLElement>('commentTextAreaRef')
8181
82+
// Those `watchEffect()`s should run once each time the respective elements get created
8283
watchEffect(() => {
83-
const commentEl = commentTextAreaRef.value?.shadowRoot?.querySelector('textarea')
84-
const els = [commentEl].filter(Boolean)
85-
86-
els.forEach((el) => {
84+
formRef.value &&
8785
useEventListener(
88-
el,
86+
formRef.value,
8987
'keydown',
9088
(ev) => {
91-
if (ev.key === 'Escape') {
92-
patchCommentForm.value[selectedRevision.id] = {
93-
comment: patchCommentForm.value[selectedRevision.id]?.comment || '',
94-
status: 'off',
95-
}
96-
}
9789
if (ev.key === 'Enter' && (ev.ctrlKey || ev.metaKey)) {
9890
submitPatchCommentForm()
91+
} else if (ev.key === 'Escape') {
92+
pausePatchCommenting()
93+
} else if (ev.key === 'p' && ev.altKey) {
94+
togglePreviewMarkdown()
9995
}
10096
},
10197
{ passive: true },
10298
)
99+
})
100+
watchEffect(() => {
101+
if (patchCommentForm.value[selectedRevision.id]?.status === 'editing') {
102+
const el = commentTextAreaRef.value
103+
setTimeout(() => el?.focus(), 0) // Vue.nextTick isn't cutting it
103104
useEventListener(el, 'focus', alignViewportWithForm, { passive: true })
104105
useEventListener(el, 'input', alignViewportWithForm, { passive: true })
105-
})
106+
}
106107
})
107108
108109
function alignViewportWithForm() {
109110
formRef.value?.scrollIntoView({ block: 'nearest', behavior: 'instant' })
110111
}
111112
112-
watchEffect(() => {
113-
if (patchCommentForm.value[selectedRevision.id]?.status === 'editing') {
114-
setTimeout(() => commentTextAreaRef.value?.focus(), 0) // Vue.nextTick isn't cutting it
115-
}
116-
})
117-
118113
interface VscodeTextAreaEvent {
119114
target: { _value: string }
120115
}
@@ -125,6 +120,13 @@ function updatePatchCommentFormComment(ev: VscodeTextAreaEvent) {
125120
}
126121
}
127122
123+
function pausePatchCommenting() {
124+
patchCommentForm.value[selectedRevision.id] = {
125+
comment: patchCommentForm.value[selectedRevision.id]?.comment || '',
126+
status: 'off',
127+
}
128+
}
129+
128130
function submitPatchCommentForm() {
129131
const commentIdsBefore = commentRefs.value?.map((commentRef) => commentRef.$attrs.id)
130132
@@ -153,6 +155,22 @@ function discardPatchCommentForm() {
153155
delete patchCommentForm.value[selectedRevision.id]
154156
}
155157
158+
function togglePreviewMarkdown() {
159+
const selectedRevForm = patchCommentForm.value[selectedRevision.id]
160+
if (selectedRevForm?.status === 'editing') {
161+
selectedRevForm.status = 'previewing'
162+
163+
if (formRef.value) {
164+
formRef.value.tabIndex = 0 // allows <form>, otherwise non-tabbable, to be `focus()`ed
165+
formRef.value.focus() // make form keyboard shortcuts still work after toggling MD preview
166+
formRef.value.tabIndex = -1 // clean-up
167+
}
168+
} else if (selectedRevForm?.status === 'previewing') {
169+
selectedRevForm.status = 'editing'
170+
setTimeout(() => commentTextAreaRef.value?.focus(), 0)
171+
}
172+
}
173+
156174
// TODO: show "edited" indicators + timestamp (on hover) or full-blown list of edits, for each revision, comment, etc anything that has edits
157175
</script>
158176

@@ -162,17 +180,28 @@ function discardPatchCommentForm() {
162180
<h2 v-if="showHeading" class="text-lg font-normal mt-0 mb-4">Activity</h2>
163181
<EventList>
164182
<EventItem
165-
v-if="patchCommentForm[selectedRevision.id]?.status === 'editing'"
183+
v-if="
184+
patchCommentForm[selectedRevision.id]?.status === 'editing' ||
185+
patchCommentForm[selectedRevision.id]?.status === 'previewing'
186+
"
166187
:when="NaN"
167188
codicon="codicon-comment"
168189
>
169190
<form
170191
@submit.prevent
171192
ref="formRef"
172193
name="Edit patch title and description"
173-
class="pb-2 flex flex-col gap-y-3"
194+
class="font-mono text-sm leading-[unset] pb-2 flex flex-col gap-y-3 outline-none"
195+
:class="{ 'w-fit': patchCommentForm[selectedRevision.id]?.status !== 'previewing' }"
196+
style="
197+
min-width: min(
198+
100%,
199+
68ch
200+
); /* results in allowing 65 chars before resizing to be wider */
201+
"
174202
>
175203
<vscode-text-area
204+
v-if="patchCommentForm[selectedRevision.id]?.status === 'editing'"
176205
ref="commentTextAreaRef"
177206
:value="patchCommentForm[selectedRevision.id]?.comment"
178207
@input="updatePatchCommentFormComment"
@@ -183,25 +212,75 @@ function discardPatchCommentForm() {
183212
>
184213
New Patch Comment:
185214
</vscode-text-area>
215+
216+
<div
217+
v-if="patchCommentForm[selectedRevision.id]?.status === 'previewing'"
218+
class="p-1 border border-dashed border-[var(--vscode-focusBorder,var(--vscode-commandCenter-debuggingBackground))] max-w-fit flex flex-col gap-y-4 group"
219+
>
220+
<Markdown
221+
:source="patchCommentForm[selectedRevision.id]?.comment || ''"
222+
class="text-sm"
223+
/>
224+
</div>
225+
186226
<div class="reset-font opacity-[0.65]"
187227
>Target Revision: <pre class="ml-1">{{ shortenHash(selectedRevision.id) }}</pre>
188228
</div>
189229

190-
<div class="w-full flex flex-row-reverse justify-start gap-x-2">
191-
<vscode-button
192-
appearance="primary"
193-
title="Save New Comment to Radicle"
194-
@click="submitPatchCommentForm"
195-
>
196-
Comment
197-
</vscode-button>
198-
<vscode-button
199-
appearance="secondary"
200-
title="Stop Editing and Discard Current Changes"
201-
@click="discardPatchCommentForm"
202-
>
203-
Discard
204-
</vscode-button>
230+
<div class="w-full flex flex-row-reverse justify-between">
231+
<div class="flex flex-row-reverse justify-start gap-x-2">
232+
<vscode-button
233+
@click="submitPatchCommentForm"
234+
appearance="primary"
235+
title="Save New Comment to Radicle"
236+
>
237+
<!-- eslint-disable-next-line vue/no-deprecated-slot-attribute -->
238+
<span slot="start" class="codicon codicon-save"></span>
239+
Comment
240+
</vscode-button>
241+
<vscode-button
242+
@click="pausePatchCommenting"
243+
appearance="secondary"
244+
title="Pause Editing, Preserving Current Changes for Later (Escape)"
245+
>
246+
<!-- eslint-disable-next-line vue/no-deprecated-slot-attribute -->
247+
<span class="codicon codicon-coffee"></span>
248+
</vscode-button>
249+
<vscode-button
250+
@click="discardPatchCommentForm"
251+
appearance="secondary"
252+
title="Stop Editing and Discard Current Changes"
253+
>
254+
<!-- eslint-disable-next-line vue/no-deprecated-slot-attribute -->
255+
<span slot="start" class="codicon codicon-discard"></span>
256+
Discard
257+
</vscode-button>
258+
</div>
259+
<div class="flex flex-row-reverse justify-start gap-x-2">
260+
<vscode-button
261+
@click="togglePreviewMarkdown"
262+
:appearance="
263+
patchCommentForm[selectedRevision.id]?.status === 'previewing'
264+
? 'primary'
265+
: 'secondary'
266+
"
267+
:title="
268+
patchCommentForm[selectedRevision.id]?.status === 'previewing'
269+
? 'Stop Previewing as Rendered Markdown and Return to Editing (Alt + P)'
270+
: 'Preview Changes as Rendered Markdown (Alt + P)'
271+
"
272+
class="self-center"
273+
>
274+
<span
275+
:class="[
276+
'codicon',
277+
patchCommentForm[selectedRevision.id]?.status === 'previewing'
278+
? 'codicon-edit'
279+
: 'codicon-markdown',
280+
]"
281+
></span>
282+
</vscode-button>
283+
</div>
205284
</div>
206285
</form>
207286
</EventItem>
@@ -370,11 +449,6 @@ function discardPatchCommentForm() {
370449
</template>
371450

372451
<style scoped>
373-
form {
374-
@apply w-fit font-mono text-sm leading-[unset];
375-
min-width: min(100%, 68ch); /* results to allowing 65 chars before resizing to be wider */
376-
}
377-
378452
.reset-font {
379453
font-family: var(--vscode-font-family);
380454
font-size: var(--vscode-font-size);

src/webviews/src/components/PatchDetailTitleDescription.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ const isAuthedToEditTitleAndDescr = computed(() => {
158158
]"
159159
>
160160
<h1 class="my-0 text-3xl font-mono"><Markdown :source="patchEditForm.title" /></h1>
161-
<Markdown v-if="patchEditForm.descr" :source="patchEditForm.descr" class="text-sm" />
161+
<Markdown :source="patchEditForm.descr" class="text-sm" />
162162
</div>
163163

164164
<vscode-text-area

0 commit comments

Comments
 (0)