add visual flourish
This commit is contained in:
parent
e2c5eab08b
commit
cbd131cc69
6 changed files with 184 additions and 114 deletions
|
@ -6,7 +6,8 @@
|
||||||
openWallet,
|
openWallet,
|
||||||
} from "$lib/wallet.svelte";
|
} from "$lib/wallet.svelte";
|
||||||
import { browser } from "$app/environment";
|
import { browser } from "$app/environment";
|
||||||
import { onMount } from "svelte";
|
import { onMount, tick } from "svelte";
|
||||||
|
import { fly } from "svelte/transition";
|
||||||
|
|
||||||
let { onunlock }: { onunlock: () => void } = $props();
|
let { onunlock }: { onunlock: () => void } = $props();
|
||||||
|
|
||||||
|
@ -14,8 +15,11 @@
|
||||||
let password = $state("");
|
let password = $state("");
|
||||||
let error = $state("");
|
let error = $state("");
|
||||||
let isValidating = $state(false);
|
let isValidating = $state(false);
|
||||||
|
let show = $state(false);
|
||||||
|
|
||||||
onMount(() => {
|
onMount(async () => {
|
||||||
|
show = true;
|
||||||
|
await tick();
|
||||||
dialogEl?.showModal();
|
dialogEl?.showModal();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -41,45 +45,50 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<dialog bind:this={dialogEl}>
|
{#if show}
|
||||||
<h2>Unlock Wallet</h2>
|
<dialog
|
||||||
<p>Enter your wallet password to decrypt your seed.</p>
|
bind:this={dialogEl}
|
||||||
{#if error}
|
transition:fly={{ y: 250, duration: 250, delay: 0.5 }}
|
||||||
<p
|
>
|
||||||
style="color: var(--error-color); font-size: 0.7rem; margin-bottom: 1rem;"
|
<h2>Unlock Wallet</h2>
|
||||||
>
|
<p>Enter your wallet password to decrypt your seed.</p>
|
||||||
{error}
|
{#if error}
|
||||||
</p>
|
<p
|
||||||
{/if}
|
style="color: var(--error-color); font-size: 0.7rem; margin-bottom: 1rem;"
|
||||||
<input
|
>
|
||||||
type="password"
|
{error}
|
||||||
class="retro-input"
|
</p>
|
||||||
bind:value={password}
|
{/if}
|
||||||
placeholder="Password"
|
<input
|
||||||
disabled={isValidating}
|
type="password"
|
||||||
onkeydown={(e) => {
|
class="retro-input"
|
||||||
if (e.key === "Enter" && !isValidating) {
|
bind:value={password}
|
||||||
attemptUnlock();
|
placeholder="Password"
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<div style="margin-top:1rem;text-align:center;">
|
|
||||||
<button
|
|
||||||
class="retro-btn primary"
|
|
||||||
disabled={isValidating}
|
disabled={isValidating}
|
||||||
onclick={() => {
|
onkeydown={(e) => {
|
||||||
attemptUnlock();
|
if (e.key === "Enter" && !isValidating) {
|
||||||
}}>{isValidating ? "Validating..." : "Unlock"}</button
|
attemptUnlock();
|
||||||
>
|
}
|
||||||
</div>
|
}}
|
||||||
</dialog>
|
/>
|
||||||
|
<div style="margin-top:1rem;text-align:center;">
|
||||||
|
<button
|
||||||
|
class="retro-btn primary"
|
||||||
|
disabled={isValidating}
|
||||||
|
onclick={() => {
|
||||||
|
attemptUnlock();
|
||||||
|
}}>{isValidating ? "Validating..." : "Unlock"}</button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</dialog>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
dialog {
|
dialog {
|
||||||
z-index: 2000;
|
z-index: 2000;
|
||||||
}
|
}
|
||||||
dialog::backdrop {
|
dialog::backdrop {
|
||||||
background: rgba(0, 0, 0, 1);
|
background: transparent;
|
||||||
}
|
}
|
||||||
h2 {
|
h2 {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
|
|
88
src/lib/components/ToggleSwitch.svelte
Normal file
88
src/lib/components/ToggleSwitch.svelte
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
<script lang="ts">
|
||||||
|
let {
|
||||||
|
label,
|
||||||
|
checked = $bindable(),
|
||||||
|
}: {
|
||||||
|
label: string;
|
||||||
|
checked: boolean;
|
||||||
|
} = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="switch-container">
|
||||||
|
<span class="switch-label">{label}</span>
|
||||||
|
<label class="switch">
|
||||||
|
<input type="checkbox" bind:checked />
|
||||||
|
<div class="track">
|
||||||
|
<div class="knob" />
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.switch-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0.5rem 0;
|
||||||
|
font-family: "Press Start 2P", monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch-label {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: 90px;
|
||||||
|
height: 40px;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch input {
|
||||||
|
opacity: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.track {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(
|
||||||
|
145deg,
|
||||||
|
var(--surface-alt-color) 0%,
|
||||||
|
#1a1a1a 100%
|
||||||
|
);
|
||||||
|
border: 3px solid var(--accent-color);
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 2px 2px 0 #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch:active .track {
|
||||||
|
transform: translate(1px, 1px);
|
||||||
|
box-shadow: 1px 1px 0 #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.knob {
|
||||||
|
position: absolute;
|
||||||
|
top: 2px;
|
||||||
|
left: 2px;
|
||||||
|
width: 40px;
|
||||||
|
height: 30px;
|
||||||
|
background: linear-gradient(145deg, var(--primary-color) 0%, #d4af00 100%);
|
||||||
|
border: 2px solid #000;
|
||||||
|
border-radius: 2px;
|
||||||
|
transition: transform 0.2s ease-in-out;
|
||||||
|
z-index: 1;
|
||||||
|
box-shadow:
|
||||||
|
inset 0 0 2px rgba(255, 255, 255, 0.3),
|
||||||
|
inset 0 0 5px rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
input:checked ~ .track .knob {
|
||||||
|
transform: translateX(41px);
|
||||||
|
}
|
||||||
|
</style>
|
28
src/lib/settings.svelte.ts
Normal file
28
src/lib/settings.svelte.ts
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import { persistentDbWritable } from "$lib/index";
|
||||||
|
import type { Writable } from "svelte/store";
|
||||||
|
import Dexie, { type Table } from "dexie";
|
||||||
|
|
||||||
|
interface MetaEntry {
|
||||||
|
key: string;
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
class SettingsDB extends Dexie {
|
||||||
|
meta!: Table<MetaEntry, string>;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super("settings");
|
||||||
|
this.version(1).stores({
|
||||||
|
meta: "&key"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const settingsDB = new SettingsDB();
|
||||||
|
|
||||||
|
export const shaderEnabled: Writable<boolean> = persistentDbWritable<boolean, SettingsDB>(
|
||||||
|
"shaderEnabled",
|
||||||
|
true,
|
||||||
|
|
||||||
|
settingsDB
|
||||||
|
);
|
|
@ -31,8 +31,7 @@ body {
|
||||||
letter-spacing: 0.5px;
|
letter-spacing: 0.5px;
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
text-shadow: 1px 1px 0 #000;
|
text-shadow: 1px 1px 0 #000;
|
||||||
overflow-x: hidden;
|
overflow: hidden;
|
||||||
overflow-y: auto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-wrapper {
|
.app-wrapper {
|
||||||
|
@ -44,14 +43,6 @@ body {
|
||||||
padding: 2rem 1rem 4rem;
|
padding: 2rem 1rem 4rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 28rem;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: stretch;
|
|
||||||
}
|
|
||||||
|
|
||||||
.send-receive-buttons {
|
.send-receive-buttons {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 0.75rem;
|
gap: 0.75rem;
|
||||||
|
@ -68,6 +59,9 @@ body {
|
||||||
box-shadow:
|
box-shadow:
|
||||||
0 0 0 4px #000,
|
0 0 0 4px #000,
|
||||||
0 0 0 8px var(--primary-color);
|
0 0 0 8px var(--primary-color);
|
||||||
|
.header {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.retro-card::before {
|
.retro-card::before {
|
||||||
|
|
|
@ -10,6 +10,9 @@
|
||||||
import SplashScreen from "$lib/components/SplashScreen.svelte";
|
import SplashScreen from "$lib/components/SplashScreen.svelte";
|
||||||
import ErrorDialog from "$lib/components/ErrorDialog.svelte";
|
import ErrorDialog from "$lib/components/ErrorDialog.svelte";
|
||||||
import InstallPrompt from "$lib/components/InstallPrompt.svelte";
|
import InstallPrompt from "$lib/components/InstallPrompt.svelte";
|
||||||
|
import { online } from "$lib/online.svelte";
|
||||||
|
import Offline from "$lib/components/Offline.svelte";
|
||||||
|
import { shaderEnabled } from "$lib/settings.svelte";
|
||||||
|
|
||||||
type AppError = {
|
type AppError = {
|
||||||
message: string;
|
message: string;
|
||||||
|
@ -93,7 +96,7 @@
|
||||||
<title>Portal BTC</title>
|
<title>Portal BTC</title>
|
||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
<div class="retro-shader">
|
<div class="container" class:retro-shader={$shaderEnabled}>
|
||||||
{#if !$online}
|
{#if !$online}
|
||||||
<Offline />
|
<Offline />
|
||||||
{:else if showInstallPrompt && deferredPrompt}
|
{:else if showInstallPrompt && deferredPrompt}
|
||||||
|
@ -121,81 +124,20 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@keyframes flicker {
|
.container {
|
||||||
0% {
|
height: 100vh;
|
||||||
opacity: 0.27861;
|
max-height: 100vh;
|
||||||
}
|
width: 100vw;
|
||||||
5% {
|
overflow-y: auto;
|
||||||
opacity: 0.34769;
|
|
||||||
}
|
|
||||||
10% {
|
|
||||||
opacity: 0.23604;
|
|
||||||
}
|
|
||||||
15% {
|
|
||||||
opacity: 0.90626;
|
|
||||||
}
|
|
||||||
20% {
|
|
||||||
opacity: 0.18128;
|
|
||||||
}
|
|
||||||
25% {
|
|
||||||
opacity: 0.83891;
|
|
||||||
}
|
|
||||||
30% {
|
|
||||||
opacity: 0.65583;
|
|
||||||
}
|
|
||||||
35% {
|
|
||||||
opacity: 0.67807;
|
|
||||||
}
|
|
||||||
40% {
|
|
||||||
opacity: 0.26559;
|
|
||||||
}
|
|
||||||
45% {
|
|
||||||
opacity: 0.84693;
|
|
||||||
}
|
|
||||||
50% {
|
|
||||||
opacity: 0.96019;
|
|
||||||
}
|
|
||||||
55% {
|
|
||||||
opacity: 0.08594;
|
|
||||||
}
|
|
||||||
60% {
|
|
||||||
opacity: 0.20313;
|
|
||||||
}
|
|
||||||
65% {
|
|
||||||
opacity: 0.71988;
|
|
||||||
}
|
|
||||||
70% {
|
|
||||||
opacity: 0.53455;
|
|
||||||
}
|
|
||||||
75% {
|
|
||||||
opacity: 0.37288;
|
|
||||||
}
|
|
||||||
80% {
|
|
||||||
opacity: 0.71428;
|
|
||||||
}
|
|
||||||
85% {
|
|
||||||
opacity: 0.70428;
|
|
||||||
}
|
|
||||||
90% {
|
|
||||||
opacity: 0.7003;
|
|
||||||
}
|
|
||||||
95% {
|
|
||||||
opacity: 0.36108;
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
opacity: 0.24387;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.retro-shader {
|
.retro-shader {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 100vh;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.retro-shader::before {
|
.retro-shader::before {
|
||||||
content: " ";
|
content: " ";
|
||||||
display: block;
|
display: block;
|
||||||
position: absolute;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
@ -212,13 +154,14 @@
|
||||||
background-size:
|
background-size:
|
||||||
100% 2px,
|
100% 2px,
|
||||||
3px 100%;
|
3px 100%;
|
||||||
|
background-attachment: fixed;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.retro-shader::after {
|
.retro-shader::after {
|
||||||
content: " ";
|
content: " ";
|
||||||
display: block;
|
display: block;
|
||||||
position: absolute;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
@ -227,7 +170,6 @@
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
z-index: 2001;
|
z-index: 2001;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
animation: flicker 0.15s infinite;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.settings-button-container {
|
.settings-button-container {
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
import LightningSettings from "$lib/components/LightningSettings.svelte";
|
import LightningSettings from "$lib/components/LightningSettings.svelte";
|
||||||
import NostrWalletConnect from "$lib/components/NostrWalletConnect.svelte";
|
import NostrWalletConnect from "$lib/components/NostrWalletConnect.svelte";
|
||||||
import DangerZone from "$lib/components/DangerZone.svelte";
|
import DangerZone from "$lib/components/DangerZone.svelte";
|
||||||
|
import { shaderEnabled } from "$lib/settings.svelte";
|
||||||
|
import ToggleSwitch from "$lib/components/ToggleSwitch.svelte";
|
||||||
|
|
||||||
function goBack() {
|
function goBack() {
|
||||||
goto("/");
|
goto("/");
|
||||||
|
@ -22,6 +24,13 @@
|
||||||
|
|
||||||
<NostrWalletConnect />
|
<NostrWalletConnect />
|
||||||
|
|
||||||
|
<details class="retro-card" open>
|
||||||
|
<summary class="header">
|
||||||
|
<h2>Design</h2>
|
||||||
|
</summary>
|
||||||
|
<ToggleSwitch label="Shader" bind:checked={$shaderEnabled} />
|
||||||
|
</details>
|
||||||
|
|
||||||
<div class="retro-card">
|
<div class="retro-card">
|
||||||
<h2>Source Code</h2>
|
<h2>Source Code</h2>
|
||||||
<Button
|
<Button
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue