Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions ts/routes/reviewer/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<!--
Copyright: Ankitects Pty Ltd and contributors
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
-->
<script lang="ts">
import "./index.scss";

import { onMount } from "svelte";
import { ReviewerState } from "./reviewer";
import ReviewerBottom from "./reviewer-bottom/ReviewerBottom.svelte";
import Reviewer from "./Reviewer.svelte";
import { _blockDefaultDragDropBehavior } from "../../reviewer";
import { checkNightMode } from "@tslib/nightmode";

const state = new ReviewerState();
const nightMode = checkNightMode();

onMount(() => {
globalThis.anki ??= {};
globalThis.anki.changeReceived = () => state.showQuestion(null);
_blockDefaultDragDropBehavior();
});
</script>

<div>
<Reviewer {state} {nightMode}></Reviewer>
<ReviewerBottom {state}></ReviewerBottom>
</div>

<style>
div {
height: 100vh;
display: flex;
flex-direction: column;
}
</style>
67 changes: 67 additions & 0 deletions ts/routes/reviewer/Reviewer.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<!--
Copyright: Ankitects Pty Ltd and contributors
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
-->
<script lang="ts">
import type { ReviewerState } from "./reviewer";

let iframe: HTMLIFrameElement;
export let state: ReviewerState;
export let nightMode = false;

$: if (iframe) {
state.registerIFrame(iframe);
state.registerShortcuts();
}
$: tooltipMessage = state.tooltipMessage;
$: tooltipShown = state.tooltipShown;
$: flag = state.flag;
$: marked = state.marked;
</script>

<div class="iframe-container">
<iframe
src={"/_anki/pages/reviewer-inner.html" + (nightMode ? "#night" : "")}
bind:this={iframe}
title="card"
frameborder="0"
sandbox="allow-scripts"
></iframe>

<div class="tooltip" style:opacity={$tooltipShown ? 1 : 0}>
{$tooltipMessage}
</div>
</div>

{#if $flag}
<div id="_flag" style:color={`var(--flag-${$flag})`}>⚑</div>
{/if}

{#if $marked}
<div id="_mark">★</div>
{/if}

<style lang="scss">
div.iframe-container {
position: relative;
flex: 1;
}

div.tooltip {
position: absolute;
left: 0;
bottom: 0;
padding: 0.8em;
background-color: var(--bs-tooltip-color);
z-index: var(--bs-tooltip-z-index);
border: 2px solid var(--highlight-fg);
opacity: 1;
transition: opacity 0.3s;
}

iframe {
width: 100%;
height: 100%;
visibility: hidden;
}
</style>
1 change: 1 addition & 0 deletions ts/routes/reviewer/index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@use "../../reviewer/reviewer.scss";
Empty file added ts/routes/reviewer/index.ts
Empty file.
102 changes: 102 additions & 0 deletions ts/routes/reviewer/reviewer-bottom/ReviewerBottom.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<!--
Copyright: Ankitects Pty Ltd and contributors
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
-->
<script lang="ts">
import "./index.scss";

import AnswerButton from "./AnswerButton.svelte";
import * as tr from "@generated/ftl";
import type { ReviewerState } from "../reviewer";
import Remaining from "./Remaining.svelte";
import More from "./More.svelte";
import Timer from "./Timer.svelte";

export let state: ReviewerState;

const _answerButtons = state.answerButtons;
const answerShown = state.answerShown;
$: answerButtons = $_answerButtons ?? [undefined, undefined, undefined, undefined];

$: buttonCount = $answerShown ? answerButtons.length : 1;
$: cardData = state.cardData;
$: remainingShown =
($cardData?.queue?.learningCount ?? 0) +
($cardData?.queue?.reviewCount ?? 0) +
($cardData?.queue?.newCount ?? 0) >
0;
</script>

<div id="outer" class="fancy">
<div id="tableinner" style="--answer-button-count: {buttonCount}">
<span class="disappearing"></span>
<div class="disappearing edit">
<button
title={tr.actionsShortcutKey({ val: "E" })}
on:click={() => state.displayEditMenu()}
>
{tr.studyingEdit()}
</button>
</div>
{#if $answerShown}
{#each answerButtons as answerButton, i}
<AnswerButton {state} due={answerButton} rating={i}></AnswerButton>
{/each}
{:else}
{#if remainingShown}
<Remaining {state}></Remaining>
{:else}
<span>&nbsp;</span>
{/if}
<button on:click={() => state.showAnswer()}>
{tr.studyingShowAnswer()}
</button>
{/if}
<div class="disappearing more">
{#if $cardData?.timer}
<Timer {state}></Timer>
{/if}
</div>
<div class="disappearing more">
<More {state}></More>
</div>
</div>
</div>

<style lang="scss">
#tableinner {
width: 100%;
display: grid;
grid-template-columns: 1fr repeat(var(--answer-button-count, 1), auto) 1fr;
grid-template-rows: auto auto;
justify-content: space-between;
justify-items: center;
align-items: center;
grid-auto-flow: column;
}

#outer {
padding: 8px;
}

.more,
.edit {
width: 100%;
}

.more {
display: flex;
justify-content: flex-end;
}

@media (max-width: 583px) {
.disappearing {
display: none;
}

#tableinner {
grid-template-columns: repeat(var(--answer-button-count, 1), auto);
justify-content: center;
}
}
</style>
Loading