frontend: make animations optional

This commit is contained in:
hippoz 2022-05-05 15:33:22 +03:00
parent 97fa63199e
commit b084de7ffc
Signed by: hippoz
GPG key ID: 7C52899193467641
13 changed files with 53 additions and 28 deletions

View file

@ -0,0 +1,12 @@
import { fade, fly } from "svelte/transition";
import { getItem } from "./storage";
export function maybeFly(...e) {
if (getItem("doAnimations"))
return fly(...e);
}
export function maybeFade(...e) {
if (getItem("doAnimations"))
return fade(...e);
}

View file

@ -49,7 +49,7 @@
<div class="message">
<span class="author">{ message.author_username }</span>
<span class="message-content" class:pending={ message._isPending }>{ message.content }</span>
{#if $userInfoStore && message.author_id === $userInfoStore.id}
{#if userInfoStore.value && message.author_id === userInfoStore.value.id}
<button class="icon-button icon-button-auto edit-message" on:click="{ () => overlayStore.open('editMessage', { message }) }">
<MoreVerticalIcon />
</button>

View file

@ -2,6 +2,7 @@
import { HashIcon, PlusIcon, MoreVerticalIcon, SettingsIcon } from "svelte-feather-icons";
import { quadInOut } from "svelte/easing";
import { fly } from "svelte/transition";
import { maybeFade } from "../animations";
import { channels, overlayStore, selectedChannel, showChannelView, showSidebar, smallViewport, userInfoStore } from "../stores";
import UserTopBar from "./UserTopBar.svelte";
@ -30,7 +31,7 @@
};
</script>
<div class="sidebar-container" transition:fly="{{ duration: 200, easing: quadInOut, x: -10 }}" on:outroend="{ outroEnd }">
<div class="sidebar-container" transition:maybeFade="{{ duration: 200, easing: quadInOut, x: -10 }}" on:outroend="{ outroEnd }">
<UserTopBar />
<div class="sidebar">
{#each $channels as channel (channel.id)}

View file

@ -4,6 +4,7 @@
import { overlayStore } from "../../stores";
import request from "../../request";
import { apiRoute } from "../../storage";
import { maybeFly } from "../../animations";
let username = "";
let password = "";
@ -52,7 +53,7 @@
</style>
<div class="modal-backdrop modal-backdrop-opaque">
<div class="modal" transition:fly="{{ duration: 300, easing: quintInOut, y: 10 }}" on:click|stopPropagation on:outroend="{ outroEnd }">
<div class="modal" transition:maybeFly="{{ duration: 300, easing: quintInOut, y: 10 }}" on:click|stopPropagation on:outroend="{ outroEnd }">
<div class="modal-header">
<span class="h4">Create an Account</span>
</div>

View file

@ -4,6 +4,7 @@
import { overlayStore } from "../../stores";
import request from "../../request";
import { apiRoute } from "../../storage";
import { maybeFade, maybeFly } from "../../animations";
let channelName = "";
let createButtonEnabled = true;
@ -29,8 +30,8 @@
}
</style>
<div class="modal-backdrop" transition:fade="{{ duration: 300, easing: quintInOut }}" on:click="{ close }">
<div class="modal" transition:fly="{{ duration: 300, easing: quintInOut, y: 10 }}" on:click|stopPropagation>
<div class="modal-backdrop" transition:maybeFade="{{ duration: 300, easing: quintInOut }}" on:click="{ close }">
<div class="modal" transition:maybeFly="{{ duration: 300, easing: quintInOut, y: 10 }}" on:click|stopPropagation>
<div class="modal-header">
<span class="h4">Create Channel</span>
</div>

View file

@ -1,5 +1,6 @@
<script>
import { fade, fly } from "svelte/transition";
import { maybeFade, maybeFly } from "../../animations";
import { quintInOut } from "svelte/easing";
import { overlayStore } from "../../stores";
import request from "../../request";
@ -45,8 +46,8 @@
}
</style>
<div class="modal-backdrop" transition:fade="{{ duration: 300, easing: quintInOut }}" on:click="{ close }">
<div class="modal" transition:fly="{{ duration: 300, easing: quintInOut, y: 10 }}" on:click|stopPropagation>
<div class="modal-backdrop" transition:maybeFade="{{ duration: 300, easing: quintInOut }}" on:click="{ close }">
<div class="modal" transition:maybeFly="{{ duration: 300, easing: quintInOut, y: 10 }}" on:click|stopPropagation>
<div class="modal-header">
<span class="h4">Edit Channel</span>
</div>

View file

@ -4,6 +4,7 @@
import { overlayStore } from "../../stores";
import request from "../../request";
import { apiRoute } from "../../storage";
import { maybeFade, maybeFly } from "../../animations";
export let message;
@ -45,8 +46,8 @@
}
</style>
<div class="modal-backdrop" transition:fade="{{ duration: 300, easing: quintInOut }}" on:click="{ close }">
<div class="modal" transition:fly="{{ duration: 300, easing: quintInOut, y: 10 }}" on:click|stopPropagation>
<div class="modal-backdrop" transition:maybeFade="{{ duration: 300, easing: quintInOut }}" on:click="{ close }">
<div class="modal" transition:maybeFly="{{ duration: 300, easing: quintInOut, y: 10 }}" on:click|stopPropagation>
<div class="modal-header">
<span class="h4">Edit Message</span>
</div>

View file

@ -5,6 +5,7 @@
import request from "../../request";
import { apiRoute } from "../../storage";
import { authWithToken } from "../../auth";
import { maybeFly } from "../../animations";
let username = "";
let password = "";
@ -56,7 +57,7 @@
</style>
<div class="modal-backdrop modal-backdrop-opaque">
<div class="modal" transition:fly="{{ duration: 300, easing: quintInOut, y: 10 }}" on:click|stopPropagation on:outroend="{ outroEnd }">
<div class="modal" transition:maybeFly="{{ duration: 300, easing: quintInOut, y: 10 }}" on:click|stopPropagation on:outroend="{ outroEnd }">
<div class="modal-header">
<span class="h4">Welcome back!</span>
</div>

View file

@ -4,6 +4,7 @@
import { AtSignIcon } from "svelte-feather-icons";
import { overlayStore, userInfoStore, smallViewport } from "../../stores";
import { logOut } from "../../auth";
import { maybeFade, maybeFly } from "../../animations";
const close = () => overlayStore.close("settings");
@ -44,8 +45,8 @@
}
</style>
<div class="modal-backdrop" transition:fade="{{ duration: 300, easing: quintInOut }}" on:click="{ close }">
<div class="modal" class:large-settings="{ !$smallViewport }" transition:fly="{{ duration: 300, easing: quintInOut, y: 10 }}" on:click|stopPropagation>
<div class="modal-backdrop" transition:maybeFade="{{ duration: 300, easing: quintInOut }}" on:click="{ close }">
<div class="modal" class:large-settings="{ !$smallViewport }" transition:maybeFly="{{ duration: 300, easing: quintInOut, y: 10 }}" on:click|stopPropagation>
<span class="h4">Account</span>
<div class="separator" />

View file

@ -2,6 +2,7 @@
import { XIcon } from "svelte-feather-icons";
import { quintInOut } from "svelte/easing";
import { fly } from "svelte/transition";
import { maybeFly } from "../../animations";
import { overlayStore } from "../../stores";
export let message;
@ -24,7 +25,7 @@
</style>
{#key message}
<div class="toast" transition:fly="{{ duration: 300, easing: quintInOut, y: 10 }}">
<div class="toast" transition:maybeFly="{{ duration: 300, easing: quintInOut, y: 10 }}">
<span>{ message }</span>
<button class="icon-button icon-button-auto" on:click="{ () => overlayStore.close('toast') }">
<XIcon />

View file

@ -127,6 +127,9 @@ export default {
log("close");
};
this.ws.onerror = (e) => {
log("websocket: onerror", e);
};
return true;
},

View file

@ -1,6 +1,7 @@
const defaults = {
apiBase: `${window.location.origin}/api/v1`,
gatewayBase: `${location.protocol === "https:" ? "wss" : "ws"}://${location.host}/gateway`
gatewayBase: `${location.protocol === "https:" ? "wss" : "ws"}://${location.host}/gateway`,
doAnimations: true
};
const dummyProvider = {
@ -39,7 +40,7 @@ export function apiRoute(fragment) {
export function setItemIfNull(key, value) {
const provider = getProvider();
if (!provider.getItem(key)) {
if (provider.getItem(key) === undefined) {
provider.setItem(key, value);
return true;
}

View file

@ -3,19 +3,20 @@ import logging from "./logging";
import request from "./request";
import { apiRoute } from "./storage";
const storeLog = logging.logger("Store");
const storeLog = logging.logger("Store", true);
class Store {
constructor(value=null) {
constructor(value=null, name="[unnamed]") {
this._handlers = [];
this.value = value;
this.name = name;
}
subscribe(handler) {
const newLength = this._handlers.push(handler);
const handlerIndex = newLength - 1;
storeLog(`(${this.name}) Calling handler (initial)`, this.value);
handler(this.value);
storeLog("Subscription initialized with value", this.value);
return () => {
this._handlers.splice(handlerIndex, 1);
};
@ -27,7 +28,7 @@ class Store {
}
updated() {
storeLog(`updated(): calling ${this._handlers.length} handlers - value changed`, this.value);
storeLog(`(${this.name}) Calling all (${this._handlers.length}) handlers (updated)`, this.value);
this._handlers.forEach(e => {
e(this.value);
});
@ -36,7 +37,7 @@ class Store {
class ChannelsStore extends Store {
constructor() {
super(gateway.channels || []);
super(gateway.channels || [], "ChannelsStore");
gateway.subscribe(GatewayEventType.Ready, ({ channels }) => {
this.value = channels;
@ -88,7 +89,7 @@ class ChannelsStore extends Store {
class GatewayStatusStore extends Store {
constructor() {
super({ open: gateway.open, ready: gateway.authenticated });
super({ open: gateway.open, ready: gateway.authenticated }, "GatewayStatusStore");
gateway.subscribe(GatewayEventType.Open, () => {
this.value.open = true;
@ -110,7 +111,7 @@ class GatewayStatusStore extends Store {
class UserInfoStore extends Store {
constructor() {
super(null);
super(null, "UserInfoStore");
gateway.subscribe(GatewayEventType.Ready, ({ user }) => {
this.value = user;
@ -121,7 +122,7 @@ class UserInfoStore extends Store {
class MessageStore extends Store {
constructor(channelId) {
super([]);
super([], `MessageStore[channelId=${channelId}]`);
this.channelId = channelId;
this.isCollectingOldMessages = true;
this.didDoInitialLoad = false;
@ -271,7 +272,7 @@ class OverlayStore extends Store {
login: null,
createAccount: null,
settings: null
});
}, "OverlayStore");
}
open(name, props={}) {
@ -285,10 +286,10 @@ class OverlayStore extends Store {
}
}
export const selectedChannel = new Store({ id: -1, name: "none", creator_id: -1 });
export const showSidebar = new Store(false);
export const showChannelView = new Store(true);
export const smallViewport = new Store(false);
export const selectedChannel = new Store({ id: -1, name: "none", creator_id: -1 }, "selectedChannel");
export const showSidebar = new Store(false, "showSidebar");
export const showChannelView = new Store(true, "showChannelView");
export const smallViewport = new Store(false, "smallViewport");
export const channels = new ChannelsStore();
export const gatewayStatus = new GatewayStatusStore();
export const messagesStoreProvider = new MessagesStoreProvider();