Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Overhaul] Implementation of a more consistent & modern UI #899

Merged
merged 48 commits into from
Mar 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
ae527dc
UPDATE: Refactored each gui "view" into a separate file, so it is les…
KyleKlus Feb 9, 2024
ce4ed19
FIX: Rewrote the keydown handler to make it a bit nicer
KyleKlus Feb 9, 2024
63fdb93
UPDATE: formatted code
KyleKlus Feb 9, 2024
7ab1605
UPDATE: Documented changes
KyleKlus Feb 9, 2024
fefcd9f
FIX: Fixed a bug where the keydown handler didn't ignore a key if the…
KyleKlus Feb 9, 2024
5e18164
UPDATE: Reimplemented the title in the decks list and implemented a w…
KyleKlus Feb 11, 2024
7103830
UPDATE: Updated class naming scheme
KyleKlus Feb 11, 2024
14568d8
UPDATE: Changed the deck list header style a bit
KyleKlus Feb 11, 2024
d21464e
UPDATE: cleaned some old code
KyleKlus Feb 11, 2024
5a0c261
UPDATE: Another bit of code cleanup
KyleKlus Feb 11, 2024
4196d62
FIX: Fixed that the close button wasn't clickable
KyleKlus Feb 11, 2024
daa3143
UPDATE: Redesigned DecksListView
KyleKlus Feb 11, 2024
c796795
UPDATE: Updated the DecksListView design
KyleKlus Feb 11, 2024
bce8450
UPDATE: Major reimplantation of the FlashcardsReviewView & again smal…
KyleKlus Feb 11, 2024
2ab3c10
UPDATE: Redesigned the edit modal
KyleKlus Feb 12, 2024
ac57c9f
UPDATED: Renamed files, such that the naming convention is the same e…
KyleKlus Feb 12, 2024
dbdcbff
UPDATE: Code cleanup & added comment
KyleKlus Feb 12, 2024
8c97e39
UPDATE: Added modal styles to the edit modal & commented the styles file
KyleKlus Feb 12, 2024
24d4838
UPDATE: Documented code changes
KyleKlus Feb 12, 2024
f760230
Merge branch 'st3v3nmw:master' into ui-overhaul
KyleKlus Feb 12, 2024
a5387e9
FIX: Fixed that the overflow behavior cause the buttons to move
KyleKlus Feb 12, 2024
7456b38
UPDATE: formatted with prettier
KyleKlus Feb 12, 2024
985d3d7
FIX: Fixed mobile view
KyleKlus Feb 12, 2024
9421db0
FIX: Fixed that mobile view wasn't spanning the whole screen, like it…
KyleKlus Feb 12, 2024
1d0ca4b
Merge branch 'small-ui-overhaul' into ui-overhaul
KyleKlus Feb 12, 2024
e56fa6d
UPDATE: Formatted with prettier
KyleKlus Feb 12, 2024
f81e81d
Merge branch 'small-ui-overhaul' into ui-overhaul
KyleKlus Feb 12, 2024
7333920
UPDATE: Shortened changelog as requested in the review
KyleKlus Feb 18, 2024
9cde10c
FIX: Fixed unused variables warning
KyleKlus Feb 18, 2024
970f99e
FIX: Title was hidden for some reason
KyleKlus Feb 18, 2024
be1f1f4
UPDATE: Used is-mobile class, instead of is-phone
KyleKlus Feb 18, 2024
15bb2cc
UPDATE: Improved backbutton position
KyleKlus Feb 18, 2024
33b035a
UPDATE: Improved context positioning
KyleKlus Feb 18, 2024
85570b3
Merge branch 'small-ui-overhaul' into ui-overhaul
KyleKlus Feb 18, 2024
cfcbc39
FIX: Implemented a better close condition
KyleKlus Feb 18, 2024
ad479a1
FIX: removed debug code
KyleKlus Feb 18, 2024
e1afbf8
FIX: Fixed that the keydown handler did respond, even if the window w…
KyleKlus Feb 18, 2024
c149bbc
Merge branch 'master' of github.com:KyleKlus/obsidian-spaced-repetiti…
KyleKlus Mar 6, 2024
9e277b8
Merge branch 'small-ui-overhaul' into ui-overhaul
KyleKlus Mar 7, 2024
2742cc2
Merge branch 'master' into small-ui-overhaul
st3v3nmw Mar 10, 2024
505dfbc
Merge branch 'master' into small-ui-overhaul
KyleKlus Mar 11, 2024
d02eb58
Merge branch 'small-ui-overhaul' into ui-overhaul
KyleKlus Mar 11, 2024
600a46e
UPDATE: Updated changelog & formatted code
KyleKlus Mar 11, 2024
1620e72
FIX: Fixed parts, as requested in review
KyleKlus Mar 14, 2024
3a65eba
Merge branch 'master' into ui-overhaul
KyleKlus Mar 19, 2024
8d591fa
Update changelog.md
KyleKlus Mar 20, 2024
79a7247
UPDATE: Added issue links to the changelog & formatted files
KyleKlus Mar 20, 2024
57ecb45
Merge branch 'master' into ui-overhaul
st3v3nmw Mar 20, 2024
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
6 changes: 3 additions & 3 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).

#### [Unreleased]

- Overhauled ui as described in issue [`#872`](https://github.com/st3v3nmw/obsidian-spaced-repetition/issues/872)
- Fixes key listener bug from issue [`#907`](https://github.com/st3v3nmw/obsidian-spaced-repetition/issues/907)
- Fixes bug from issue [`#773`](https://github.com/st3v3nmw/obsidian-spaced-repetition/issues/773)
- Unrelated Tags in Card Selection Modal since version 1.12.0 [`#908`](https://github.com/st3v3nmw/obsidian-spaced-repetition/issues/908)

#### [1.12.0](https://github.com/st3v3nmw/obsidian-spaced-repetition/compare/1.11.2...1.12.0)
Expand Down Expand Up @@ -33,9 +36,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).

#### [1.11.1](https://github.com/st3v3nmw/obsidian-spaced-repetition/compare/1.11.0...1.11.1)

> 22 January 2024

- Bump version to v1.11.1 [`#854`](https://github.com/st3v3nmw/obsidian-spaced-repetition/pull/854)
- chore: fix README to point to new project board [`#848`](https://github.com/st3v3nmw/obsidian-spaced-repetition/pull/848)
- chore: update pt-br.ts for Brazilian Portuguese translation [`#765`](https://github.com/st3v3nmw/obsidian-spaced-repetition/pull/765)
- chore: update dependencies [`#845`](https://github.com/st3v3nmw/obsidian-spaced-repetition/pull/845)
Expand Down
236 changes: 236 additions & 0 deletions src/gui/DeckListView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import h from "vhtml";

import type SRPlugin from "src/main";
import { SRSettings } from "src/settings";
import { COLLAPSE_ICON } from "src/constants";
import { t } from "src/lang/helpers";
import { Deck } from "../Deck";
import {
DeckStats,
IFlashcardReviewSequencer as IFlashcardReviewSequencer,
} from "src/FlashcardReviewSequencer";
import { TopicPath } from "src/TopicPath";
import { FlashcardModalMode } from "./FlashcardModal";

export class DeckListView {
public plugin: SRPlugin;
public mode: FlashcardModalMode;
public modalContentEl: HTMLElement;

public view: HTMLDivElement;
public header: HTMLDivElement;
public title: HTMLDivElement;
public stats: HTMLDivElement;
public content: HTMLDivElement;

private reviewSequencer: IFlashcardReviewSequencer;
private settings: SRSettings;
private startReviewOfDeck: (deck: Deck) => void;

constructor(
plugin: SRPlugin,
settings: SRSettings,
reviewSequencer: IFlashcardReviewSequencer,
contentEl: HTMLElement,
startReviewOfDeck: (deck: Deck) => void,
) {
// Init properties
this.plugin = plugin;
this.settings = settings;
this.reviewSequencer = reviewSequencer;
this.modalContentEl = contentEl;
this.startReviewOfDeck = startReviewOfDeck;

// Build ui
this.init();
}

/**
* Initializes all static elements in the DeckListView
*/
init(): void {
this.view = this.modalContentEl.createDiv();
this.view.addClasses(["sr-deck-list", "sr-is-hidden"]);

this.header = this.view.createDiv();
this.header.addClass("sr-header");

this.title = this.header.createDiv();
this.title.addClass("sr-title");
this.title.setText(t("DECKS"));

this.stats = this.header.createDiv();
this.stats.addClass("sr-header-stats-container");
this._createHeaderStats();

this.content = this.view.createDiv();
this.content.addClass("sr-content");
}

/**
* Shows the DeckListView & rerenders dynamic elements
*/
show(): void {
this.mode = FlashcardModalMode.DecksList;

// Redraw in case the stats have changed
this._createHeaderStats();

this.content.empty();
for (const deck of this.reviewSequencer.originalDeckTree.subdecks) {
this._createTree(deck, this.content);
}

if (this.view.hasClass("sr-is-hidden")) {
this.view.removeClass("sr-is-hidden");
}
}

/**
* Hides the DeckListView
*/
hide() {
if (!this.view.hasClass("sr-is-hidden")) {
this.view.addClass("sr-is-hidden");
}
}

/**
* Closes the DeckListView
*/
close() {
this.hide();
}

// -> Header

private _createHeaderStats() {
const statistics: DeckStats = this.reviewSequencer.getDeckStats(TopicPath.emptyPath);
this.stats.empty();

this._createHeaderStatsContainer(t("TOTAL_CARDS"), statistics.totalCount, "sr-bg-red");
this._createHeaderStatsContainer(t("NEW_CARDS"), statistics.newCount, "sr-bg-blue");
this._createHeaderStatsContainer(t("DUE_CARDS"), statistics.dueCount, "sr-bg-green");
}

private _createHeaderStatsContainer(
statsLable: string,
statsNumber: number,
statsClass: string,
): void {
const statsContainer = this.stats.createDiv();
statsContainer.ariaLabel = statsLable;
statsContainer.addClasses([
"tag-pane-tag-count",
"tree-item-flair",
"sr-header-stats-count",
statsClass,
]);

const lable = statsContainer.createDiv();
lable.setText(statsLable + ":");

const number = statsContainer.createDiv();
number.setText(statsNumber.toString());
}

// -> Tree content

private _createTree(deck: Deck, container: HTMLElement): void {
const deckTree: HTMLElement = container.createDiv("tree-item sr-tree-item-container");
const deckTreeSelf: HTMLElement = deckTree.createDiv(
"tree-item-self tag-pane-tag is-clickable sr-tree-item-row",
);

const shouldBeInitiallyExpanded: boolean = this.settings.initiallyExpandAllSubdecksInTree;
let collapsed = !shouldBeInitiallyExpanded;
let collapseIconEl: HTMLElement | null = null;
if (deck.subdecks.length > 0) {
collapseIconEl = deckTreeSelf.createDiv("tree-item-icon collapse-icon");
collapseIconEl.innerHTML = COLLAPSE_ICON;
(collapseIconEl.childNodes[0] as HTMLElement).style.transform = collapsed
? "rotate(-90deg)"
: "";
}

const deckTreeInner: HTMLElement = deckTreeSelf.createDiv("tree-item-inner");
const deckTreeInnerText: HTMLElement = deckTreeInner.createDiv("tag-pane-tag-text");
deckTreeInnerText.innerHTML += <span class="tag-pane-tag-self">{deck.deckName}</span>;

const deckTreeOuter: HTMLDivElement = deckTreeSelf.createDiv();
deckTreeOuter.addClasses(["tree-item-flair-outer", "sr-tree-stats-container"]);

const deckStats = this.reviewSequencer.getDeckStats(deck.getTopicPath());
this._createStats(deckStats, deckTreeOuter);

const deckTreeChildren: HTMLElement = deckTree.createDiv("tree-item-children");
deckTreeChildren.style.display = collapsed ? "none" : "block";
if (deck.subdecks.length > 0) {
collapseIconEl.addEventListener("click", (e) => {
if (collapsed) {
(collapseIconEl.childNodes[0] as HTMLElement).style.transform = "";
deckTreeChildren.style.display = "block";
} else {
(collapseIconEl.childNodes[0] as HTMLElement).style.transform =
"rotate(-90deg)";
deckTreeChildren.style.display = "none";
}

// We stop the propagation of the event so that the click event for deckTreeSelf doesn't get called
// if the user clicks on the collapse icon
e.stopPropagation();
collapsed = !collapsed;
});
}

// Add the click handler to deckTreeSelf instead of deckTreeInner so that it activates
// over the entire rectangle of the tree item, not just the text of the topic name
// https://github.com/st3v3nmw/obsidian-spaced-repetition/issues/709
deckTreeSelf.addEventListener("click", () => {
this.startReviewOfDeck(deck);
});

for (const subdeck of deck.subdecks) {
this._createTree(subdeck, deckTreeChildren);
}
}

private _createStats(statistics: DeckStats, statsWrapper: HTMLDivElement) {
statsWrapper.empty();

this._createStatsContainer(
t("TOTAL_CARDS"),
statistics.totalCount,
"sr-bg-red",
statsWrapper,
);
this._createStatsContainer(t("NEW_CARDS"), statistics.newCount, "sr-bg-blue", statsWrapper);
this._createStatsContainer(
t("DUE_CARDS"),
statistics.dueCount,
"sr-bg-green",
statsWrapper,
);
}

private _createStatsContainer(
statsLable: string,
statsNumber: number,
statsClass: string,
statsWrapper: HTMLDivElement,
): void {
const statsContainer = statsWrapper.createDiv();

statsContainer.ariaLabel = statsLable;

statsContainer.addClasses([
"tag-pane-tag-count",
"tree-item-flair",
"sr-tree-stats-count",
statsClass,
]);

statsContainer.setText(statsNumber.toString());
}
}
Loading
Loading