Visual indication that a page is loading

pull/73/head
Zef Hemel 2022-09-06 16:21:33 +02:00
parent 101d124115
commit 0090db37e6
5 changed files with 36 additions and 6 deletions

View File

@ -1,4 +1,9 @@
import { faRunning, faHome, faSun, faMoon } from "@fortawesome/free-solid-svg-icons"; import {
faRunning,
faHome,
faSun,
faMoon,
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { Notification } from "../types"; import { Notification } from "../types";
@ -13,6 +18,7 @@ function prettyName(s: string | undefined): string {
export function TopBar({ export function TopBar({
pageName, pageName,
unsavedChanges, unsavedChanges,
isLoading,
notifications, notifications,
onClick, onClick,
onThemeClick, onThemeClick,
@ -23,6 +29,7 @@ export function TopBar({
}: { }: {
pageName?: string; pageName?: string;
unsavedChanges: boolean; unsavedChanges: boolean;
isLoading: boolean;
notifications: Notification[]; notifications: Notification[];
onClick: () => void; onClick: () => void;
onThemeClick: () => void; onThemeClick: () => void;
@ -31,8 +38,7 @@ export function TopBar({
lhs?: React.ReactNode; lhs?: React.ReactNode;
rhs?: React.ReactNode; rhs?: React.ReactNode;
}) { }) {
const [theme, setTheme] = useState<string>(localStorage.theme ?? "light");
const [theme, setTheme] = useState<string>(localStorage.theme ?? 'light');
return ( return (
<div id="sb-top" onClick={onClick}> <div id="sb-top" onClick={onClick}>
@ -41,7 +47,11 @@ export function TopBar({
<div className="inner"> <div className="inner">
<span <span
className={`sb-current-page ${ className={`sb-current-page ${
unsavedChanges ? "sb-unsaved" : "sb-saved" isLoading
? "sb-loading"
: unsavedChanges
? "sb-unsaved"
: "sb-saved"
}`} }`}
> >
{prettyName(pageName)} {prettyName(pageName)}
@ -80,12 +90,12 @@ export function TopBar({
<button <button
onClick={(e) => { onClick={(e) => {
onThemeClick(); onThemeClick();
setTheme(localStorage.theme ?? 'light'); setTheme(localStorage.theme ?? "light");
e.stopPropagation(); e.stopPropagation();
}} }}
title="Toggle theme" title="Toggle theme"
> >
<FontAwesomeIcon icon={theme === 'dark' ? faSun : faMoon} /> <FontAwesomeIcon icon={theme === "dark" ? faSun : faMoon} />
</button> </button>
</div> </div>
</div> </div>

View File

@ -610,6 +610,11 @@ export class Editor {
return; return;
} }
this.viewDispatch({
type: "page-loading",
name: pageName,
});
// Persist current page state and nicely close page // Persist current page state and nicely close page
if (this.currentPage) { if (this.currentPage) {
this.saveState(); this.saveState();
@ -768,6 +773,7 @@ export class Editor {
pageName={viewState.currentPage} pageName={viewState.currentPage}
notifications={viewState.notifications} notifications={viewState.notifications}
unsavedChanges={viewState.unsavedChanges} unsavedChanges={viewState.unsavedChanges}
isLoading={viewState.isLoading}
onClick={() => { onClick={() => {
dispatch({ type: "start-navigate" }); dispatch({ type: "start-navigate" });
}} }}

View File

@ -9,9 +9,16 @@ export default function reducer(
): AppViewState { ): AppViewState {
// console.log("Got action", action); // console.log("Got action", action);
switch (action.type) { switch (action.type) {
case "page-loading":
return {
...state,
isLoading: true,
currentPage: action.name,
};
case "page-loaded": case "page-loaded":
return { return {
...state, ...state,
isLoading: false,
allPages: new Set( allPages: new Set(
[...state.allPages].map((pageMeta) => [...state.allPages].map((pageMeta) =>
pageMeta.name === action.meta.name pageMeta.name === action.meta.name

View File

@ -40,6 +40,10 @@
color: #5e5e5e; color: #5e5e5e;
} }
.sb-loading {
color: #7a7a7a;
}
.sb-actions button { .sb-actions button {
border: 1px solid #7897d0; border: 1px solid #7897d0;
border-radius: 3px; border-radius: 3px;

View File

@ -12,6 +12,7 @@ export type AppViewState = {
currentPage?: string; currentPage?: string;
perm: "ro" | "rw"; perm: "ro" | "rw";
isLoading: boolean;
showPageNavigator: boolean; showPageNavigator: boolean;
showCommandPalette: boolean; showCommandPalette: boolean;
unsavedChanges: boolean; unsavedChanges: boolean;
@ -39,6 +40,7 @@ export type AppViewState = {
export const initialViewState: AppViewState = { export const initialViewState: AppViewState = {
perm: "rw", perm: "rw",
isLoading: false,
showPageNavigator: false, showPageNavigator: false,
showCommandPalette: false, showCommandPalette: false,
unsavedChanges: false, unsavedChanges: false,
@ -62,6 +64,7 @@ export const initialViewState: AppViewState = {
export type Action = export type Action =
| { type: "page-loaded"; meta: PageMeta } | { type: "page-loaded"; meta: PageMeta }
| { type: "page-loading"; name: string }
| { type: "pages-listed"; pages: Set<PageMeta> } | { type: "pages-listed"; pages: Set<PageMeta> }
| { type: "page-changed" } | { type: "page-changed" }
| { type: "page-saved" } | { type: "page-saved" }