fix(anki): allow timing review cards without media

- Keep existing or create new cards without generating audio or images
- Refine timing review timeline expansion labels and boundary markers
This commit is contained in:
2026-08-30 01:56:16 -07:00
parent 046ab59da9
commit 475f81d96d
14 changed files with 204 additions and 40 deletions
+21 -5
View File
@@ -271,6 +271,12 @@
<span class="media-timing-review-original-boundary is-start"></span>
<span class="media-timing-review-original-boundary is-end"></span>
</div>
<span class="media-timing-review-original-label is-start" aria-hidden="true">
Line start
</span>
<span class="media-timing-review-original-label is-end" aria-hidden="true">
Line end
</span>
<div
id="mediaTimingReviewSelectedRange"
class="media-timing-review-selected-range"
@@ -299,18 +305,20 @@
id="mediaTimingReviewShowEarlier"
class="media-timing-review-expand-button"
type="button"
aria-label="Reveal five more seconds before the timeline"
aria-label="Show two more seconds before the visible timeline without moving the selected clip"
title="Show 2 more seconds before the visible timeline. The selected clip does not move."
>
&minus;5s
Earlier &minus;2s
</button>
<span>Drag an edge to trim, or drag the middle to slide the clip.</span>
<span>Drag an edge to trim, or drag the highlighted clip to move it.</span>
<button
id="mediaTimingReviewShowLater"
class="media-timing-review-expand-button"
type="button"
aria-label="Reveal five more seconds after the timeline"
aria-label="Show two more seconds after the visible timeline without moving the selected clip"
title="Show 2 more seconds after the visible timeline. The selected clip does not move."
>
+5s
Later +2s
</button>
</div>
</div>
@@ -411,6 +419,14 @@
>
Use original timing
</button>
<button
id="mediaTimingReviewSkipMedia"
class="media-timing-review-skip-button"
type="button"
title="Keep this card but do not add audio or an image."
>
Keep without media
</button>
<button
id="mediaTimingReviewDiscard"
class="media-timing-review-discard-button"
+9 -3
View File
@@ -5,7 +5,7 @@ import { createModalFocusGuard } from './modal-focus-guard';
const MINIMUM_CLIP_SECONDS = 0.1;
const FINE_ADJUST_SECONDS = 0.1;
const COARSE_ADJUST_SECONDS = 0.5;
const TIMELINE_EXPANSION_SECONDS = 5;
const TIMELINE_EXPANSION_SECONDS = 2;
function clamp(value: number, minimum: number, maximum: number): number {
return Math.min(maximum, Math.max(minimum, value));
@@ -447,8 +447,10 @@ export function createMediaTimingReviewModal(
ctx.dom.mediaTimingReviewCancelStep.classList.remove('hidden');
ctx.dom.mediaTimingReviewCancelMessage.textContent =
payload.noteId !== undefined
? 'Keep editing, finish this card with its original timing, or delete the card.'
: 'Keep editing, finish this card with its original timing, or do not create it.';
? 'Keep editing, keep this card without media, use its original timing, or delete it.'
: 'Keep editing, create this card without media, use its original timing, or do not create it.';
ctx.dom.mediaTimingReviewSkipMedia.textContent =
payload.noteId !== undefined ? 'Keep without media' : 'Create without media';
ctx.dom.mediaTimingReviewDiscard.textContent =
payload.noteId !== undefined ? 'Delete card' : "Don't create card";
ctx.dom.mediaTimingReviewCancelBack.focus();
@@ -668,6 +670,10 @@ export function createMediaTimingReviewModal(
'click',
() => void resolveReview({ action: 'use-original' }),
);
ctx.dom.mediaTimingReviewSkipMedia.addEventListener(
'click',
() => void resolveReview({ action: 'skip-media' }),
);
ctx.dom.mediaTimingReviewDiscard.addEventListener(
'click',
() => void resolveReview({ action: 'discard' }),
+18 -8
View File
@@ -1594,30 +1594,32 @@ body:focus-visible,
right: 0;
}
.media-timing-review-original-boundary::after {
.media-timing-review-original-label {
position: absolute;
z-index: 7;
padding: 3px 5px;
border: 1px solid color-mix(in srgb, var(--ctp-crust) 35%, transparent);
border-radius: 4px;
background: var(--ctp-peach);
box-shadow: 0 2px 6px color-mix(in srgb, var(--ctp-crust) 55%, transparent);
color: var(--ctp-crust);
font-size: 8px;
font-weight: 800;
letter-spacing: 0.06em;
line-height: 1;
pointer-events: none;
white-space: nowrap;
text-transform: uppercase;
}
.media-timing-review-original-boundary.is-start::after {
.media-timing-review-original-label.is-start {
top: 5px;
left: 5px;
content: 'line start';
left: calc(var(--original-start) + 7px);
}
.media-timing-review-original-boundary.is-end::after {
right: 5px;
.media-timing-review-original-label.is-end {
right: calc(100% - var(--original-end) + 7px);
bottom: 5px;
content: 'line end';
}
.media-timing-review-track.is-loading::after {
@@ -1749,6 +1751,7 @@ body:focus-visible,
.media-timing-review-expand-button,
.media-timing-review-quiet-button,
.media-timing-review-original-button,
.media-timing-review-skip-button,
.media-timing-review-discard-button,
.media-timing-review-play-button,
.media-timing-review-confirm-button,
@@ -1768,7 +1771,8 @@ body:focus-visible,
}
.media-timing-review-expand-button {
padding: 5px 10px;
min-width: 82px;
padding: 5px 9px;
color: var(--ctp-sky);
font-variant-numeric: tabular-nums;
}
@@ -1853,6 +1857,7 @@ body:focus-visible,
.media-timing-review-confirm-button,
.media-timing-review-quiet-button,
.media-timing-review-original-button,
.media-timing-review-skip-button,
.media-timing-review-discard-button {
padding: 9px 15px;
}
@@ -1897,6 +1902,11 @@ body:focus-visible,
color: var(--ctp-yellow);
}
.media-timing-review-skip-button {
border-color: var(--ctp-sky);
color: var(--ctp-sky);
}
.media-timing-review-discard-button {
border-color: var(--ctp-red);
background: var(--ctp-red);
+2
View File
@@ -75,6 +75,7 @@ export type RendererDom = {
mediaTimingReviewCancelMessage: HTMLParagraphElement;
mediaTimingReviewCancelBack: HTMLButtonElement;
mediaTimingReviewUseOriginal: HTMLButtonElement;
mediaTimingReviewSkipMedia: HTMLButtonElement;
mediaTimingReviewDiscard: HTMLButtonElement;
kikuModal: HTMLDivElement;
@@ -292,6 +293,7 @@ export function resolveRendererDom(): RendererDom {
mediaTimingReviewUseOriginal: getRequiredElement<HTMLButtonElement>(
'mediaTimingReviewUseOriginal',
),
mediaTimingReviewSkipMedia: getRequiredElement<HTMLButtonElement>('mediaTimingReviewSkipMedia'),
mediaTimingReviewDiscard: getRequiredElement<HTMLButtonElement>('mediaTimingReviewDiscard'),
kikuModal: getRequiredElement<HTMLDivElement>('kikuFieldGroupingModal'),