add visual flourish

This commit is contained in:
Danny Morabito 2025-07-17 18:50:41 +02:00
parent e2c5eab08b
commit cbd131cc69
Signed by: dannym
GPG key ID: 7CC8056A5A04557E
6 changed files with 184 additions and 114 deletions

View file

@ -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;

View 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>

View 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
);

View file

@ -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 {

View file

@ -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 {

View file

@ -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