Compare commits
No commits in common. "72c9650f7142945e367dd916aa55a7303e30cfa3" and "94e94deb912a88b220e6093adc2adc99257e0d0c" have entirely different histories.
72c9650f71
...
94e94deb91
11 changed files with 299 additions and 264 deletions
|
@ -1,22 +1,8 @@
|
||||||
import { fade, fly, scale } from "svelte/transition";
|
import { fade, fly, scale } from "svelte/transition";
|
||||||
import { cubicInOut, linear } from "svelte/easing";
|
import { cubicInOut } from "svelte/easing";
|
||||||
import { getItem } from "./storage";
|
import { getItem } from "./storage";
|
||||||
import { smallViewport } from "./stores";
|
import { smallViewport } from "./stores";
|
||||||
|
|
||||||
|
|
||||||
// Function specific for the Login and CreateAccount modals, where the transition duration is relied upon
|
|
||||||
export function maybeModalFadeIf(...e) {
|
|
||||||
if (e[1] && e[1]._condition)
|
|
||||||
return maybeModalFade(e[0]);
|
|
||||||
else
|
|
||||||
return {
|
|
||||||
delay: 0,
|
|
||||||
duration: e[1].duration,
|
|
||||||
easing: e[1].easing,
|
|
||||||
css: (_t) => ""
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function maybeModalFade(node) {
|
export function maybeModalFade(node) {
|
||||||
return maybeFade(node, { duration: 175, easing: cubicInOut });
|
return maybeFade(node, { duration: 175, easing: cubicInOut });
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { overlayStore } from "../../stores";
|
import { overlayStore } from "../../stores";
|
||||||
import { methods, remoteSignal } from "../../request";
|
import { methods, remoteSignal } from "../../request";
|
||||||
import Modal from "./Modal.svelte";
|
import { maybeModalFade, maybeModalScale } from "../../animations";
|
||||||
|
|
||||||
let communityName = "";
|
let communityName = "";
|
||||||
let createButtonEnabled = true;
|
let createButtonEnabled = true;
|
||||||
|
@ -15,20 +15,36 @@
|
||||||
}
|
}
|
||||||
close();
|
close();
|
||||||
};
|
};
|
||||||
|
const onKeydown = async (e) => {
|
||||||
|
if (e.code !== "Enter")
|
||||||
|
return;
|
||||||
|
|
||||||
|
await create();
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Modal {close} enter={create}>
|
<style>
|
||||||
<span class="h4" slot="header">Create Community</span>
|
.full-width {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<svelte:fragment slot="content">
|
<div class="modal-backdrop" transition:maybeModalFade on:click="{ close }" on:keydown="{ onKeydown }">
|
||||||
<label class="input-label">
|
<div class="modal" transition:maybeModalScale on:click|stopPropagation>
|
||||||
Community Name
|
<div class="modal-header">
|
||||||
<input class="input full-width" minlength="1" maxlength="32" bind:value={ communityName } />
|
<span class="h4">Create Community</span>
|
||||||
</label>
|
</div>
|
||||||
</svelte:fragment>
|
|
||||||
|
|
||||||
<svelte:fragment slot="footer">
|
<div class="modal-content">
|
||||||
<button class="button modal-secondary-action" on:click="{ close }">Cancel</button>
|
<label class="input-label">
|
||||||
<button class="button button-accent modal-primary-action" on:click="{ create }" disabled="{ !createButtonEnabled }">Create</button>
|
Community Name
|
||||||
</svelte:fragment>
|
<input class="input full-width" minlength="1" maxlength="32" bind:value={ communityName } />
|
||||||
</Modal>
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button class="button modal-secondary-action" on:click="{ close }">Cancel</button>
|
||||||
|
<button class="button button-accent modal-primary-action" on:click="{ create }" disabled="{ !createButtonEnabled }">Create</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { overlayStore, OverlayType } from "../../stores";
|
import { overlayStore, OverlayType } from "../../stores";
|
||||||
import { methods, remoteCall } from "../../request";
|
import { methods, remoteCall } from "../../request";
|
||||||
import Modal from "./Modal.svelte";
|
import { maybeModalScale } from "../../animations";
|
||||||
|
|
||||||
let username = "";
|
let username = "";
|
||||||
let password = "";
|
let password = "";
|
||||||
|
@ -30,33 +30,47 @@
|
||||||
overlayStore.push(OverlayType.Login);
|
overlayStore.push(OverlayType.Login);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const onKeydown = async (e) => {
|
||||||
|
if (e.code !== "Enter")
|
||||||
|
return;
|
||||||
|
|
||||||
|
await create();
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.full-width {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.separator {
|
.separator {
|
||||||
margin-bottom: var(--space-md);
|
margin-bottom: var(--space-md);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<Modal opaque close={loginInstead} {outroEnd} enter={create}>
|
<div class="modal-backdrop modal-backdrop-opaque" on:keydown="{ onKeydown }">
|
||||||
<span class="h4" slot="header">Create an Account</span>
|
<div class="modal" transition:maybeModalScale on:click|stopPropagation on:outroend="{ outroEnd }">
|
||||||
|
<div class="modal-header">
|
||||||
|
<span class="h4">Create an Account</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<svelte:fragment slot="content">
|
<div class="modal-content">
|
||||||
<label class="input-label">
|
<label class="input-label">
|
||||||
Username
|
Username
|
||||||
<input class="input full-width" minlength="1" maxlength="32" bind:value={ username } />
|
<input class="input full-width" minlength="1" maxlength="32" bind:value={ username } />
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<div class="separator" />
|
<div class="separator" />
|
||||||
|
|
||||||
<label class="input-label">
|
<label class="input-label">
|
||||||
Password
|
Password
|
||||||
<input class="input full-width" minlength="8" type="password" bind:value={ password } />
|
<input class="input full-width" minlength="8" type="password" bind:value={ password } />
|
||||||
</label>
|
</label>
|
||||||
</svelte:fragment>
|
</div>
|
||||||
|
|
||||||
<svelte:fragment slot="footer">
|
<div class="modal-footer">
|
||||||
<button class="button modal-secondary-action" on:click="{ loginInstead }">Log in instead</button>
|
<button class="button modal-secondary-action" on:click="{ loginInstead }">Log in instead</button>
|
||||||
<button class="button button-accent modal-primary-action" on:click="{ create }" disabled="{ !buttonsEnabled }">Create</button>
|
<button class="button button-accent modal-primary-action" on:click="{ create }" disabled="{ !buttonsEnabled }">Create</button>
|
||||||
</svelte:fragment>
|
</div>
|
||||||
</Modal>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { overlayStore } from "../../stores";
|
import { overlayStore } from "../../stores";
|
||||||
import { methods, remoteSignal } from "../../request";
|
import { methods, remoteCall, remoteSignal } from "../../request";
|
||||||
import Modal from "./Modal.svelte";
|
import { maybeModalFade, maybeModalScale } from "../../animations";
|
||||||
|
|
||||||
let channelName = "";
|
let channelName = "";
|
||||||
let createButtonEnabled = true;
|
let createButtonEnabled = true;
|
||||||
|
@ -16,25 +16,39 @@
|
||||||
}
|
}
|
||||||
close();
|
close();
|
||||||
};
|
};
|
||||||
|
const onKeydown = async (e) => {
|
||||||
|
if (e.code !== "Enter")
|
||||||
|
return;
|
||||||
|
|
||||||
|
await create();
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Modal {close} enter={create}>
|
<style>
|
||||||
<svelte:fragment slot="header">
|
.full-width {
|
||||||
<span class="h4">Create Channel</span>
|
width: 100%;
|
||||||
{#if community.id !== -1}
|
}
|
||||||
<span class="text-fg-3 text-small">in <span class="text-fg-2">{ community.name }</span></span>
|
</style>
|
||||||
{/if}
|
|
||||||
</svelte:fragment>
|
|
||||||
|
|
||||||
<svelte:fragment slot="content">
|
<div class="modal-backdrop" transition:maybeModalFade on:click="{ close }" on:keydown="{ onKeydown }">
|
||||||
<label class="input-label">
|
<div class="modal" transition:maybeModalScale on:click|stopPropagation>
|
||||||
Channel Name
|
<div class="modal-header">
|
||||||
<input class="input full-width" minlength="1" maxlength="32" bind:value={ channelName } />
|
<span class="h4">Create Channel</span>
|
||||||
</label>
|
{#if community.id !== -1}
|
||||||
</svelte:fragment>
|
<span class="text-fg-3 text-small">in <span class="text-fg-2">{ community.name }</span></span>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
<svelte:fragment slot="footer">
|
<div class="modal-content">
|
||||||
<button class="button modal-secondary-action" on:click="{ close }">Cancel</button>
|
<label class="input-label">
|
||||||
<button class="button button-accent modal-primary-action" on:click="{ create }" disabled="{ !createButtonEnabled }">Create</button>
|
Channel Name
|
||||||
</svelte:fragment>
|
<input class="input full-width" minlength="1" maxlength="32" bind:value={ channelName } />
|
||||||
</Modal>
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button class="button modal-secondary-action" on:click="{ close }">Cancel</button>
|
||||||
|
<button class="button button-accent modal-primary-action" on:click="{ create }" disabled="{ !createButtonEnabled }">Create</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script>
|
<script>
|
||||||
|
import { maybeModalFade, maybeModalScale } from "../../animations";
|
||||||
import { overlayStore } from "../../stores";
|
import { overlayStore } from "../../stores";
|
||||||
import { methods, remoteSignal } from "../../request";
|
import { methods, remoteCall, remoteSignal } from "../../request";
|
||||||
import Modal from "./Modal.svelte";
|
|
||||||
|
|
||||||
export let channel;
|
export let channel;
|
||||||
|
|
||||||
|
@ -25,27 +25,41 @@
|
||||||
}
|
}
|
||||||
close();
|
close();
|
||||||
};
|
};
|
||||||
|
const onKeydown = async (e) => {
|
||||||
|
if (e.code !== "Enter")
|
||||||
|
return;
|
||||||
|
|
||||||
|
await save();
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.full-width {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.delete-button {
|
.delete-button {
|
||||||
color: var(--red-2);
|
color: var(--red-2);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<Modal {close} enter={save}>
|
<div class="modal-backdrop" transition:maybeModalFade on:click="{ close }" on:keydown="{ onKeydown }">
|
||||||
<span class="h4" slot="header">Edit Channel</span>
|
<div class="modal" transition:maybeModalScale on:click|stopPropagation>
|
||||||
|
<div class="modal-header">
|
||||||
|
<span class="h4">Edit Channel</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<svelte:fragment slot="content">
|
<div class="modal-content">
|
||||||
<label class="input-label">
|
<label class="input-label">
|
||||||
Channel Name
|
Channel Name
|
||||||
<input class="input full-width" minlength="1" maxlength="32" bind:value={ channelName } />
|
<input class="input full-width" minlength="1" maxlength="32" bind:value={ channelName } />
|
||||||
</label>
|
</label>
|
||||||
</svelte:fragment>
|
</div>
|
||||||
|
|
||||||
<svelte:fragment slot="footer">
|
<div class="modal-footer">
|
||||||
<button class="button modal-secondary-action" on:click="{ close }">Cancel</button>
|
<button class="button modal-secondary-action" on:click="{ close }">Cancel</button>
|
||||||
<button class="button modal-secondary-action delete-button" on:click="{ deleteChannel }" disabled="{ !buttonsEnabled }">Delete</button>
|
<button class="button modal-secondary-action delete-button" on:click="{ deleteChannel }" disabled="{ !buttonsEnabled }">Delete</button>
|
||||||
<button class="button button-accent modal-primary-action" on:click="{ save }" disabled="{ !buttonsEnabled }">Save</button>
|
<button class="button button-accent modal-primary-action" on:click="{ save }" disabled="{ !buttonsEnabled }">Save</button>
|
||||||
</svelte:fragment>
|
</div>
|
||||||
</Modal>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { overlayStore } from "../../stores";
|
import { overlayStore } from "../../stores";
|
||||||
import { methods, remoteSignal } from "../../request";
|
import { methods, remoteCall, remoteSignal } from "../../request";
|
||||||
import Modal from "./Modal.svelte";
|
import { maybeModalFade, maybeModalScale } from "../../animations";
|
||||||
|
|
||||||
export let message;
|
export let message;
|
||||||
|
|
||||||
|
@ -25,27 +25,41 @@
|
||||||
}
|
}
|
||||||
close();
|
close();
|
||||||
};
|
};
|
||||||
|
const onKeydown = async (e) => {
|
||||||
|
if (e.code !== "Enter")
|
||||||
|
return;
|
||||||
|
|
||||||
|
await save();
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.full-width {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.delete-button {
|
.delete-button {
|
||||||
color: var(--red-2);
|
color: var(--red-2);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<Modal {close} enter={save}>
|
<div class="modal-backdrop" transition:maybeModalFade on:click="{ close }" on:keydown="{ onKeydown }">
|
||||||
<span class="h4" slot="header">Edit Message</span>
|
<div class="modal" transition:maybeModalScale on:click|stopPropagation>
|
||||||
|
<div class="modal-header">
|
||||||
|
<span class="h4">Edit Message</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<svelte:fragment slot="content">
|
<div class="modal-content">
|
||||||
<label class="input-label">
|
<label class="input-label">
|
||||||
Content
|
Content
|
||||||
<input class="input full-width" minlength="1" bind:value={ messageContent } />
|
<input class="input full-width" minlength="1" bind:value={ messageContent } />
|
||||||
</label>
|
</label>
|
||||||
</svelte:fragment>
|
</div>
|
||||||
|
|
||||||
<svelte:fragment slot="footer">
|
<div class="modal-footer">
|
||||||
<button class="button modal-secondary-action" on:click="{ close }">Cancel</button>
|
<button class="button modal-secondary-action" on:click="{ close }">Cancel</button>
|
||||||
<button class="button modal-secondary-action delete-button" on:click="{ deleteMessage }" disabled="{ !buttonsEnabled }">Delete</button>
|
<button class="button modal-secondary-action delete-button" on:click="{ deleteMessage }" disabled="{ !buttonsEnabled }">Delete</button>
|
||||||
<button class="button button-accent modal-primary-action" on:click="{ save }" disabled="{ !buttonsEnabled }">Save</button>
|
<button class="button button-accent modal-primary-action" on:click="{ save }" disabled="{ !buttonsEnabled }">Save</button>
|
||||||
</svelte:fragment>
|
</div>
|
||||||
</Modal>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
import { overlayStore, OverlayType } from "../../stores";
|
import { overlayStore, OverlayType } from "../../stores";
|
||||||
import { remoteCall } from "../../request";
|
import { remoteCall } from "../../request";
|
||||||
import { authWithToken } from "../../auth";
|
import { authWithToken } from "../../auth";
|
||||||
|
import { maybeModalScale } from "../../animations";
|
||||||
import { methods } from "../../request";
|
import { methods } from "../../request";
|
||||||
import Modal from "./Modal.svelte";
|
|
||||||
|
|
||||||
let username = "";
|
let username = "";
|
||||||
let password = "";
|
let password = "";
|
||||||
|
@ -35,33 +35,47 @@
|
||||||
overlayStore.push(OverlayType.CreateAccount);
|
overlayStore.push(OverlayType.CreateAccount);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const onKeydown = async (e) => {
|
||||||
|
if (e.code !== "Enter")
|
||||||
|
return;
|
||||||
|
|
||||||
|
await login();
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.full-width {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.separator {
|
.separator {
|
||||||
margin-bottom: var(--space-md);
|
margin-bottom: var(--space-md);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<Modal opaque close={createAccountInstead} {outroEnd} enter={login}>
|
<div class="modal-backdrop modal-backdrop-opaque" on:keydown="{ onKeydown }">
|
||||||
<span class="h4" slot="header">Welcome back!</span>
|
<div class="modal" transition:maybeModalScale on:click|stopPropagation on:outroend="{ outroEnd }">
|
||||||
|
<div class="modal-header">
|
||||||
|
<span class="h4">Welcome back!</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<svelte:fragment slot="content">
|
<div class="modal-content">
|
||||||
<label class="input-label">
|
<label class="input-label">
|
||||||
Username
|
Username
|
||||||
<input class="input full-width" minlength="1" maxlength="32" bind:value={ username } />
|
<input class="input full-width" minlength="1" maxlength="32" bind:value={ username } />
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<div class="separator" />
|
<div class="separator" />
|
||||||
|
|
||||||
<label class="input-label">
|
<label class="input-label">
|
||||||
Password
|
Password
|
||||||
<input class="input full-width" minlength="8" type="password" bind:value={ password } />
|
<input class="input full-width" minlength="8" type="password" bind:value={ password } />
|
||||||
</label>
|
</label>
|
||||||
</svelte:fragment>
|
</div>
|
||||||
|
|
||||||
<svelte:fragment slot="footer">
|
<div class="modal-footer">
|
||||||
<button class="button modal-secondary-action" on:click="{ createAccountInstead }">Create an account instead</button>
|
<button class="button modal-secondary-action" on:click="{ createAccountInstead }">Create an account instead</button>
|
||||||
<button class="button button-accent modal-primary-action" on:click="{ login }" disabled="{ !buttonsEnabled }">Log In</button>
|
<button class="button button-accent modal-primary-action" on:click="{ login }" disabled="{ !buttonsEnabled }">Log In</button>
|
||||||
</svelte:fragment>
|
</div>
|
||||||
</Modal>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
<script>
|
|
||||||
import { onMount } from "svelte";
|
|
||||||
import { maybeModalFade, maybeModalFadeIf, maybeModalScale } from "../../animations";
|
|
||||||
|
|
||||||
export let close = () => {};
|
|
||||||
export let enter = () => {};
|
|
||||||
export let outroEnd = () => {};
|
|
||||||
export let className = "";
|
|
||||||
export let opaque = false;
|
|
||||||
let modal;
|
|
||||||
let blur = false;
|
|
||||||
|
|
||||||
const onKeydown = ({ code }) => {
|
|
||||||
if (code === "Enter") {
|
|
||||||
enter();
|
|
||||||
} else if (code === "Escape") {
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const backdropIntroEnd = () => {
|
|
||||||
blur = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
const backdropOutroStart = () => {
|
|
||||||
blur = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
onMount(() => {
|
|
||||||
modal.focus();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
||||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
|
||||||
<!-- svelte-ignore a11y-no-noninteractive-element-interactions -->
|
|
||||||
<div class="modal-backdrop" class:modal-backdrop-opaque={opaque} class:blur={blur} transition:maybeModalFadeIf="{{ _condition: !opaque }}" on:click="{ close }" on:keydown="{ onKeydown }" on:introend={backdropIntroEnd} on:outrostart={backdropOutroStart}>
|
|
||||||
<div bind:this={modal} role="alertdialog" tabindex="-1" aria-modal="true" class={className + " modal"} transition:maybeModalScale on:click|stopPropagation on:outroend={outroEnd}>
|
|
||||||
{#if $$slots.header}
|
|
||||||
<div class="modal-header">
|
|
||||||
<slot name="header" />
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{#if $$slots.content}
|
|
||||||
<div class="modal-content">
|
|
||||||
<slot name="content" />
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{#if $$slots.footer}
|
|
||||||
<div class="modal-footer">
|
|
||||||
<slot name="footer" />
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
import Modal from "./Modal.svelte";
|
import { maybeModalFade, maybeModalScale } from "../../animations";
|
||||||
|
|
||||||
export let onSubmit = async () => {};
|
export let onSubmit = async () => {};
|
||||||
export let onClose = async () => {};
|
export let onClose = async () => {};
|
||||||
|
@ -19,18 +19,36 @@
|
||||||
await onSubmit(userInput);
|
await onSubmit(userInput);
|
||||||
closePrompt();
|
closePrompt();
|
||||||
};
|
};
|
||||||
|
const onKeydown = async (e) => {
|
||||||
|
if (e.code !== "Enter")
|
||||||
|
return;
|
||||||
|
|
||||||
|
await save();
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Modal {closePrompt} enter={save}>
|
<style>
|
||||||
<span class="h4" slot="header">{ heading }</span>
|
.full-width {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<label class="input-label" slot="content">
|
<div class="modal-backdrop" transition:maybeModalFade on:click="{ closePrompt }" on:keydown="{ onKeydown }">
|
||||||
{ valueName }
|
<div class="modal" transition:maybeModalScale on:click|stopPropagation>
|
||||||
<input class="input full-width" bind:value={ userInput } />
|
<div class="modal-header">
|
||||||
</label>
|
<span class="h4">{ heading }</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<svelte:fragment slot="footer">
|
<div class="modal-content">
|
||||||
<button class="button modal-secondary-action" on:click="{ closePrompt }">Cancel</button>
|
<label class="input-label">
|
||||||
<button class="button button-accent modal-primary-action" on:click="{ save }" disabled="{ !buttonsEnabled }">Submit</button>
|
{ valueName }
|
||||||
</svelte:fragment>
|
<input class="input full-width" bind:value={ userInput } />
|
||||||
</Modal>
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button class="button modal-secondary-action" on:click="{ closePrompt }">Cancel</button>
|
||||||
|
<button class="button button-accent modal-primary-action" on:click="{ save }" disabled="{ !buttonsEnabled }">Submit</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
|
@ -2,12 +2,12 @@
|
||||||
import { overlayStore, userInfoStore, smallViewport, theme, doAnimations, OverlayType, sendTypingUpdatesItemStore } from "../../stores";
|
import { overlayStore, userInfoStore, smallViewport, theme, doAnimations, OverlayType, sendTypingUpdatesItemStore } from "../../stores";
|
||||||
import { logOut } from "../../auth";
|
import { logOut } from "../../auth";
|
||||||
import { maybeModalFade, maybeModalScale } from "../../animations";
|
import { maybeModalFade, maybeModalScale } from "../../animations";
|
||||||
import request, { methods, remoteBlobUpload } from "../../request";
|
import request, { methods, remoteBlobUpload, remoteCall } from "../../request";
|
||||||
import { apiRoute, getItem } from "../../storage";
|
import { apiRoute, getItem } from "../../storage";
|
||||||
import UserView from "../UserView.svelte";
|
import UserView from "../UserView.svelte";
|
||||||
import ChipBar from "../ChipBar.svelte";
|
import ChipBar from "../ChipBar.svelte";
|
||||||
|
import Switch from "../Switch.svelte";
|
||||||
import StoredSwitch from "../StoredSwitch.svelte";
|
import StoredSwitch from "../StoredSwitch.svelte";
|
||||||
import Modal from "./Modal.svelte";
|
|
||||||
|
|
||||||
export let close = () => {};
|
export let close = () => {};
|
||||||
let avatarFileInput;
|
let avatarFileInput;
|
||||||
|
@ -76,7 +76,12 @@
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
<style>
|
<style>
|
||||||
|
.full-width {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.separator {
|
.separator {
|
||||||
margin-bottom: var(--space-sm);
|
margin-bottom: var(--space-sm);
|
||||||
}
|
}
|
||||||
|
@ -123,7 +128,7 @@
|
||||||
grid-template-columns: repeat(2, 1fr);
|
grid-template-columns: repeat(2, 1fr);
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(.large-settings) {
|
.large-settings {
|
||||||
width: 600px;
|
width: 600px;
|
||||||
min-height: 425px;
|
min-height: 425px;
|
||||||
padding-bottom: var(--space-xs);
|
padding-bottom: var(--space-xs);
|
||||||
|
@ -133,72 +138,77 @@
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(.settings-modal) {
|
.settings-modal {
|
||||||
background-color: var(--background-color-1) !important;
|
background-color: var(--background-color-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(.settings-modal .modal-header) {
|
.settings-modal .modal-header {
|
||||||
padding-bottom: var(--space-xxs);
|
padding-bottom: var(--space-xxs);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<Modal {close} className={`settings-modal ${$smallViewport ? "" : "large-settings"}`}>
|
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||||
<span class="h4" slot="header">Settings</span>
|
<div class="modal-backdrop" transition:maybeModalFade on:click="{ close }">
|
||||||
|
<div class="modal settings-modal" class:large-settings="{ !$smallViewport }" transition:maybeModalScale on:click|stopPropagation>
|
||||||
|
<div class="modal-header">
|
||||||
|
<span class="h4">Settings</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<svelte:fragment slot="content">
|
<div class="modal-content">
|
||||||
<ChipBar selectedOptionId="ACCOUNT" onSelect={ (tab) => selectedTab = tab } options={[
|
<ChipBar selectedOptionId="ACCOUNT" onSelect={ (tab) => selectedTab = tab } options={[
|
||||||
{ id: "ACCOUNT", text: "Account", icon: "person" },
|
{ id: "ACCOUNT", text: "Account", icon: "person" },
|
||||||
{ id: "PRIVACY", text: "Privacy", icon: "lock" },
|
{ id: "PRIVACY", text: "Privacy", icon: "lock" },
|
||||||
{ id: "APPEARANCE", text: "Appearance", icon: "palette" },
|
{ id: "APPEARANCE", text: "Appearance", icon: "palette" },
|
||||||
]}></ChipBar>
|
]}></ChipBar>
|
||||||
|
|
||||||
<div class="separator" />
|
|
||||||
|
|
||||||
{#if selectedTab === "ACCOUNT"}
|
|
||||||
<div class="settings-card full-width">
|
|
||||||
<UserView user={$userInfoStore}></UserView>
|
|
||||||
<input type="file" style="display: none;" accept="image/png, image/jpeg, image/webp" name="avatar-upload" multiple={false} bind:this={avatarFileInput} on:change={onAvatarFileChange}>
|
|
||||||
<div class="left-auto">
|
|
||||||
<button class="button" on:click="{ openAvatarInput }">Update Avatar</button>
|
|
||||||
<button class="button button-danger" on:click="{ doLogout }">Log Out</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{:else if selectedTab == "PRIVACY"}
|
|
||||||
<div class="switch-option-card full-width">
|
|
||||||
<div class="info">
|
|
||||||
<span class="info-heading">Let others know when I'm typing</span>
|
|
||||||
<span class="text-fg-3 text-small">If this is enabled, other users will see an indicator while you're typing a message.</span>
|
|
||||||
</div>
|
|
||||||
<div class="option-switch">
|
|
||||||
<StoredSwitch store={ sendTypingUpdatesItemStore } />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="switch-option-card full-width">
|
|
||||||
<div class="info">
|
|
||||||
<span class="info-heading">Make Waffle work</span>
|
|
||||||
<span class="text-fg-3 text-small">Waffle needs to store data such as your messages, created channels, your username, your profile picture and more in order to work. If you'd like to stop this, you can delete your account.</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{:else if selectedTab === "APPEARANCE"}
|
|
||||||
<span class="input-label">Theme</span>
|
|
||||||
<div class="horizontal-selections">
|
|
||||||
<button class="button selection-option full-width selected" class:selected="{ $theme === "dark" }" on:click="{ () => theme.set('dark') }">Dark</button>
|
|
||||||
<button class="button selection-option full-width" class:selected="{ $theme === "light" }" on:click="{ () => theme.set('light') }">Light</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="separator" />
|
<div class="separator" />
|
||||||
|
|
||||||
<div class="switch-option-card full-width">
|
{#if selectedTab === "ACCOUNT"}
|
||||||
<div class="info">
|
<div class="settings-card full-width">
|
||||||
<span class="info-heading">Reduce animations</span>
|
<UserView user={$userInfoStore}></UserView>
|
||||||
<span class="text-fg-3 text-small">Reduce the amount of animations and visual effects.</span>
|
<input type="file" style="display: none;" accept="image/png, image/jpeg, image/webp" name="avatar-upload" multiple={false} bind:this={avatarFileInput} on:change={onAvatarFileChange}>
|
||||||
|
<div class="left-auto">
|
||||||
|
<button class="button" on:click="{ openAvatarInput }">Update Avatar</button>
|
||||||
|
<button class="button button-danger" on:click="{ doLogout }">Log Out</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="option-switch">
|
{:else if selectedTab == "PRIVACY"}
|
||||||
<StoredSwitch store={ doAnimations } inverted={ true } />
|
<div class="switch-option-card full-width">
|
||||||
|
<div class="info">
|
||||||
|
<span class="info-heading">Let others know when I'm typing</span>
|
||||||
|
<span class="text-fg-3 text-small">If this is enabled, other users will see an indicator while you're typing a message.</span>
|
||||||
|
</div>
|
||||||
|
<div class="option-switch">
|
||||||
|
<StoredSwitch store={ sendTypingUpdatesItemStore } />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="switch-option-card full-width">
|
||||||
{:else}
|
<div class="info">
|
||||||
<span>Page not found: { selectedTab }</span>
|
<span class="info-heading">Make Waffle work</span>
|
||||||
{/if}
|
<span class="text-fg-3 text-small">Waffle needs to store data such as your messages, created channels, your username, your profile picture and more in order to work. If you'd like to stop this, you can delete your account.</span>
|
||||||
</svelte:fragment>
|
</div>
|
||||||
</Modal>
|
</div>
|
||||||
|
{:else if selectedTab === "APPEARANCE"}
|
||||||
|
<span class="input-label">Theme</span>
|
||||||
|
<div class="horizontal-selections">
|
||||||
|
<button class="button selection-option full-width selected" class:selected="{ $theme === "dark" }" on:click="{ () => theme.set('dark') }">Dark</button>
|
||||||
|
<button class="button selection-option full-width" class:selected="{ $theme === "light" }" on:click="{ () => theme.set('light') }">Light</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="separator" />
|
||||||
|
|
||||||
|
<div class="switch-option-card full-width">
|
||||||
|
<div class="info">
|
||||||
|
<span class="info-heading">Reduce animations</span>
|
||||||
|
<span class="text-fg-3 text-small">Reduce the amount of animations and visual effects.</span>
|
||||||
|
</div>
|
||||||
|
<div class="option-switch">
|
||||||
|
<StoredSwitch store={ doAnimations } inverted={ true } />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<span>Page not found: { selectedTab }</span>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
|
@ -54,13 +54,13 @@
|
||||||
/* top-level */
|
/* top-level */
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--purple-1: hsl(266, 63%, 64%);
|
--purple-1: hsl(273, 67%, 53%);
|
||||||
--blue-1: hsl(200, 78%, 50%);
|
--blue-1: hsl(200, 78%, 50%);
|
||||||
--green-1: hsl(140, 78%, 50%);
|
--green-1: hsl(140, 78%, 50%);
|
||||||
--yellow-1: hsl(50, 78%, 50%);
|
--yellow-1: hsl(50, 78%, 50%);
|
||||||
--red-1: hsl(2, 78%, 65%);
|
--red-1: hsl(2, 78%, 65%);
|
||||||
|
|
||||||
--purple-2: hsl(266, 62%, 58%);
|
--purple-2: hsl(273, 64%, 48%);
|
||||||
--blue-2: hsl(200, 78%, 45%);
|
--blue-2: hsl(200, 78%, 45%);
|
||||||
--green-2: hsl(140, 78%, 40%);
|
--green-2: hsl(140, 78%, 40%);
|
||||||
--yellow-2: hsl(50, 78%, 60%);
|
--yellow-2: hsl(50, 78%, 60%);
|
||||||
|
@ -222,11 +222,8 @@ body {
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
z-index: 15;
|
z-index: 15;
|
||||||
background-color: rgba(0, 0, 0, 0.4);
|
background-color: rgba(0, 0, 0, 0.4);
|
||||||
contain: strict;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-backdrop.blur {
|
|
||||||
backdrop-filter: blur(1.5px);
|
backdrop-filter: blur(1.5px);
|
||||||
|
contain: strict;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-backdrop-opaque {
|
.modal-backdrop-opaque {
|
||||||
|
@ -287,6 +284,7 @@ body {
|
||||||
.modal-backdrop {
|
.modal-backdrop {
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
backdrop-filter: unset;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-backdrop-opaque {
|
.modal-backdrop-opaque {
|
||||||
|
@ -329,10 +327,8 @@ body {
|
||||||
background: none;
|
background: none;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border: none;
|
border: none;
|
||||||
padding: 0.85em;
|
padding: 0.7em;
|
||||||
padding-top: 0.65em;
|
border-radius: 1em;
|
||||||
padding-bottom: 0.65em;
|
|
||||||
border-radius: 9999px;
|
|
||||||
font: inherit;
|
font: inherit;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
font-weight: 550;
|
font-weight: 550;
|
||||||
|
@ -592,10 +588,6 @@ body {
|
||||||
border-bottom-left-radius: var(--radius-mdplus);
|
border-bottom-left-radius: var(--radius-mdplus);
|
||||||
}
|
}
|
||||||
|
|
||||||
.full-width {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*! the tweaks below are heavily based on modern-normalize v1.1.0 | MIT License | https://github.com/sindresorhus/modern-normalize */
|
/*! the tweaks below are heavily based on modern-normalize v1.1.0 | MIT License | https://github.com/sindresorhus/modern-normalize */
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue