Add loading view component #8

Merged
tcoh merged 1 commits from feature/loading-view into master 2022-08-29 22:24:31 +00:00
9 changed files with 64 additions and 5 deletions

View File

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-rotate-clockwise" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
<path d="M4.05 11a8 8 0 1 1 .5 4m-.5 5v-5h5" />
</svg>

After

Width:  |  Height:  |  Size: 349 B

View File

@ -17,6 +17,7 @@
--gap-large: 32px;
--duration-short: 0.3s;
--duration-long: 1.5s;
}
.grow {
@ -208,6 +209,31 @@ i {
}
}
/* Loading */
.loading-icon {
animation: spin infinite linear var(--duration-long),
fadein linear var(--duration-short);
}
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@keyframes fadein {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
/* Icon buttons */
.icon-button {
@ -306,6 +332,14 @@ i {
/* Expression set page */
.page-loading {
height: 100%;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.page-with-padding {
padding: var(--gap-small) var(--gap-medium) var(--gap-medium);
}

View File

@ -4,6 +4,7 @@ import { useAllExpressions } from "../../hooks";
import { IndexedExpression } from "../../model";
import { AppPath, AppRouting } from "../../model/routing";
import { ErrorView } from "../ErrorView";
import { LoadingView } from "../LoadingView/LoadingView";
export function ExpressionCardListView() {
const { setRoute } = useContext(AppRouting);
@ -13,7 +14,7 @@ export function ExpressionCardListView() {
[expressions]
);
if (!expressions) return null; // LOADING
if (!expressions) return <LoadingView />;
if (!expressions.length) {
return <ErrorView message="No expression cards yet" />;
}

View File

@ -3,12 +3,13 @@ import { ExpressionDescription } from "../../components/ExpressionDescription";
import { useExpressionById, useQueryExpressionId } from "../../hooks";
import { ItemNotFoundError } from "../../model";
import { ErrorView } from "../ErrorView";
import { LoadingView } from "../LoadingView/LoadingView";
export function ExpressionCardView() {
const expression_id = useQueryExpressionId();
const expression = useExpressionById(expression_id);
if (expression === undefined) return null; // LOADING
if (expression === undefined) return <LoadingView />;
if (expression === ItemNotFoundError)
return <ErrorView message="Expression card not found" />;

View File

@ -8,6 +8,7 @@ import {
import { IndexedExpression } from "../../model";
import { sample } from "../../util";
import { ErrorView } from "../ErrorView";
import { LoadingView } from "../LoadingView/LoadingView";
import { ExpressionPracticeCardView } from "./ExpressionPracticeCardView";
export function ExpressionPracticeView() {
@ -16,7 +17,7 @@ export function ExpressionPracticeView() {
const expressions = useExpressionsByExpressionSetId(expression_set_id);
// TODO handle errors
if (!expressions) return null; // LOADING
if (!expressions) return <LoadingView />;
const filtered_expressions = expressions.filter(
(expression) => !filter_ids.includes(expression.id!)

View File

@ -8,13 +8,14 @@ import {
import { IndexedExpressionSet, ItemNotFoundError } from "../../model";
import { AppPath, AppRouting } from "../../model/routing";
import { ErrorView } from "../ErrorView";
import { LoadingView } from "../LoadingView/LoadingView";
export function ExpressionSetDetailsView() {
const expression_set_id = useQueryExpressionSetId();
const expression_set = useExpressionSetById(expression_set_id);
const expressions = useExpressionsByExpressionSetId(expression_set_id);
if (!expression_set || !expressions) return null; // LOADING
if (!expression_set || !expressions) return <LoadingView />;
if (expression_set === ItemNotFoundError) {
return <ErrorView message="Expression set not found" />;
}

View File

@ -1,11 +1,12 @@
import { useAllExpressionSets } from "../../hooks";
import { ErrorView } from "../ErrorView";
import { LoadingView } from "../LoadingView/LoadingView";
import { ExpressionSetLink } from "./ExpressionSetLink";
export function ExpressionSetListView() {
const expression_sets = useAllExpressionSets();
if (!expression_sets) return null; // LOADING
if (!expression_sets) return <LoadingView />;
if (!expression_sets.length) {
return <ErrorView message="No expression sets found" />;
}

View File

@ -0,0 +1,13 @@
export function LoadingView() {
return (
<div className="page-loading">
<img
className="loading-icon"
src="/icons/rotate-clockwise.svg"
width="64"
height="64"
alt=""
/>
</div>
);
}

View File

@ -0,0 +1 @@
export * from "./LoadingView";