[POC] use serviceWorker from create-react-app (#1286)

* Service worker with toast notifications

* Update CSP to allow fetches from now.sh

* Fixed clearing timers

* rounded icon for pwa (#1301)

* rounded icon for pwa

* cirle pwa app icon

* fix fonts caching

* fix app

* fix css import

* Updated csp tp inlcude worker-src: self

* add worker CSP rule

* use square icon

Co-authored-by: Timur Khazamov <t1mmaas@skbkontur.ru>
Co-authored-by: Faustino Kialungila <Faustino.kialungila@gmail.com>
Co-authored-by: kbariotis <konmpar@gmail.com>
This commit is contained in:
Timur Khazamov 2020-04-13 16:08:39 +02:00 committed by GitHub
parent e158dbc45a
commit 4228c2e094
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 308 additions and 31 deletions

View file

@ -2652,4 +2652,3 @@ if (
}
export default App;
// -----------------------------------------------------------------------------

View file

@ -1,4 +1,4 @@
@import "../_variables";
@import "../css/_variables";
.Dialog__title {
display: grid;

View file

@ -1,4 +1,4 @@
@import "../_variables";
@import "../css/_variables";
.ExportDialog__preview {
--preview-padding: calc(var(--space-factor) * 4);

View file

@ -1,4 +1,4 @@
@import "../_variables";
@import "../css/_variables";
.HintViewer {
color: $oc-gray-6;

View file

@ -1,4 +1,4 @@
@import "../_variables";
@import "../css/_variables";
.Modal {
position: fixed;

View file

@ -1,4 +1,4 @@
@import "../_variables";
@import "../css/_variables";
.RoomDialog-modalButton.is-collaborating {
background-color: $oc-green-0;

View file

@ -1,4 +1,4 @@
@import "../_variables.scss";
@import "../css/_variables.scss";
.TextInput {
display: inline-block;

33
src/components/Toast.css Normal file
View file

@ -0,0 +1,33 @@
.Toast__container {
position: fixed;
bottom: calc(var(--space-factor) * 2);
right: calc(var(--space-factor) * 2);
left: calc(var(--space-factor) * 2);
display: flex;
justify-content: center;
z-index: 1000;
}
.Toast {
position: relative;
}
.Toast__content {
padding-right: calc(var(--space-factor) * 9);
max-width: calc(var(--space-factor) * 50);
}
.Toast__close {
position: absolute;
width: calc(var(--space-factor) * 5);
height: calc(var(--space-factor) * 5);
top: calc(var(--space-factor) * -1);
right: 0;
display: flex;
align-items: center;
justify-content: center;
}
.Toast__close svg {
height: calc(var(--space-factor) * 3);
}

97
src/components/Toast.tsx Normal file
View file

@ -0,0 +1,97 @@
import React from "react";
import { render } from "react-dom";
import Stack from "./Stack";
import { Island } from "./Island";
import "./Toast.css";
import { close } from "./icons";
const TOAST_TIMEOUT = 7000;
function ToastRenderer(props: {
toasts: Map<number, React.ReactNode>;
onCloseRequest: (id: number) => void;
}) {
return (
<Stack.Col gap={2} align="center">
{[...props.toasts.entries()].map(([id, toast]) => (
<Island key={id} padding={3}>
<div className="Toast">
<div className="Toast__content">{toast}</div>
<button
className="Toast__close"
onClick={() => props.onCloseRequest(id)}
>
{close}
</button>
</div>
</Island>
))}
</Stack.Col>
);
}
let toastsRootNode: HTMLDivElement;
function getToastsRootNode() {
return toastsRootNode || (toastsRootNode = initToastsRootNode());
}
function initToastsRootNode() {
const div = window.document.createElement("div");
document.body.appendChild(div);
div.className = "Toast__container";
return div;
}
function renderToasts(
toasts: Map<number, React.ReactNode>,
onCloseRequest: (id: number) => void,
) {
render(
<ToastRenderer toasts={toasts} onCloseRequest={onCloseRequest} />,
getToastsRootNode(),
);
}
let incrementalId = 0;
function getToastId() {
return incrementalId++;
}
class ToastManager {
private toasts = new Map<number, React.ReactNode>();
private timers = new Map<number, number>();
public push(message: React.ReactNode, shiftAfterMs: number) {
const id = getToastId();
this.toasts.set(id, message);
if (isFinite(shiftAfterMs)) {
const handle = window.setTimeout(() => this.pop(id), shiftAfterMs);
this.timers.set(id, handle);
}
this.render();
}
private pop = (id: number) => {
const handle = this.timers.get(id);
if (handle) {
window.clearTimeout(handle);
this.timers.delete(id);
}
this.toasts.delete(id);
this.render();
};
private render() {
renderToasts(this.toasts, this.pop);
}
}
let toastManagerInstance: ToastManager;
function getToastManager(): ToastManager {
return toastManagerInstance ?? (toastManagerInstance = new ToastManager());
}
export function push(message: React.ReactNode, manualClose = false) {
const toastManager = getToastManager();
toastManager.push(message, manualClose ? Infinity : TOAST_TIMEOUT);
}