diff options
| author | Adam Soltys <[email protected]> | 2024-03-19 10:23:34 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2024-03-19 10:23:34 -0700 |
| commit | a4685f61e656ed0e3cd343073931867955be3281 (patch) | |
| tree | c28c446ef0f6d5cbc37a7c58f954c145bd18ef80 /src | |
| parent | c6c2ac113186ba304c46580320df91c119ab5314 (diff) | |
| parent | e2bb9d704878070054fa8ef81da73b248e2c4f97 (diff) | |
| download | coinos-ui-a4685f61e656ed0e3cd343073931867955be3281.tar.gz coinos-ui-a4685f61e656ed0e3cd343073931867955be3281.zip | |
Merge remote-tracking branch 'muriwolf/swapee' into swapee
Diffstat (limited to 'src')
64 files changed, 1400 insertions, 544 deletions
diff --git a/src/app.css b/src/app.css index 3f0cbbd0..bcd5421c 100644 --- a/src/app.css +++ b/src/app.css @@ -1,6 +1,89 @@ +@import url('https://fonts.googleapis.com/css2?family=Bebas+Neue&display=swap'); +@import url('https://fonts.googleapis.com/css2?family=Bebas+Neue&family=Inter:wght@100;200;300;400;500;600;700;800;900&family=Work+Sans:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap'); @tailwind base; @tailwind components; @tailwind utilities; + +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 224 71.4% 4.1%; + + --muted: 220 14.3% 95.9%; + --muted-foreground: 220 8.9% 46.1%; + + --popover: 0 0% 100%; + --popover-foreground: 224 71.4% 4.1%; + + --card: 0 0% 100%; + --card-foreground: 224 71.4% 4.1%; + + --border: 220 13% 91%; + --input: 220 13% 91%; + + --primary: 220.9 39.3% 11%; + --primary-foreground: 210 20% 98%; + + --secondary: 220 14.3% 95.9%; + --secondary-foreground: 220.9 39.3% 11%; + + --accent: 220 14.3% 95.9%; + --accent-foreground: 220.9 39.3% 11%; + + --destructive: 0 72.2% 50.6%; + --destructive-foreground: 210 20% 98%; + + --ring: 224 71.4% 4.1%; + + --radius: 0.5rem; + } + + .dark { + --background: 224 71.4% 4.1%; + --foreground: 210 20% 98%; + + --muted: 215 27.9% 16.9%; + --muted-foreground: 217.9 10.6% 64.9%; + + --popover: 224 71.4% 4.1%; + --popover-foreground: 210 20% 98%; + + --card: 224 71.4% 4.1%; + --card-foreground: 210 20% 98%; + + --border: 215 27.9% 16.9%; + --input: 215 27.9% 16.9%; + + --primary: 210 20% 98%; + --primary-foreground: 220.9 39.3% 11%; + + --secondary: 215 27.9% 16.9%; + --secondary-foreground: 210 20% 98%; + + --accent: 215 27.9% 16.9%; + --accent-foreground: 210 20% 98%; + + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 210 20% 98%; + + --ring: 216 12.2% 83.9%; + } +} + +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; + } +} + +@layer components { + .input-swapee { + @apply bg-primary text-gray-700 dark:text-gray-100 dark:bg-stone-700 border-0 focus:outline-none focus:ring-2 hover:ring-2 ring-swapee-purple ring-offset-swapee-purple ease-in-out transition-all duration-500; + } +} @font-face { font-family: "PublicSans"; @@ -9,7 +92,7 @@ } html { - font-family: PublicSans, sans-serif; + font-family: 'Inter', sans-serif; } :root { @@ -29,6 +112,46 @@ html { background-color: white; } +/* SCROLL BAR */ +::-webkit-scrollbar { + width: 4px; + scrollbar-width: thin; + scrollbar-color: #f7f7f7; +} + +@media (min-width: 720px) { + ::-webkit-scrollbar { + width: 12px; + } +} + +::-webkit-scrollbar-thumb { + background-color: #222; +} + +.dark > body { + background-color: #000 +} + +.dark > body::-webkit-scrollbar-thumb { + background-color: #fff; +} + +/* to paint the profile page, because the way the page is built, the only way is to paint the body tag :/ */ +.dark > body::-webkit-scrollbar-track { + background-color: #000; +} + +input:-webkit-autofill, +input:-webkit-autofill:focus { + transition: background-color 600000s 0s, color 600000s 0s; +} +input[data-autocompleted] { + background-color: transparent !important; +} + +/* SCROLL BAR */ + input, textarea { @apply block border rounded-2xl px-5 py-4 w-full; diff --git a/src/app.html b/src/app.html index 28f07d06..475a15fb 100644 --- a/src/app.html +++ b/src/app.html @@ -2,7 +2,7 @@ <html lang="en"> <head> <meta charset="utf-8" /> - <link rel="icon" href="%sveltekit.assets%/favicon.svg" /> + <link rel="icon" href="%sveltekit.assets%/favicon.png" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" diff --git a/src/components/AppHeader.svelte b/src/components/AppHeader.svelte index 26982456..42536e62 100644 --- a/src/components/AppHeader.svelte +++ b/src/components/AppHeader.svelte @@ -41,36 +41,45 @@ {#if !$loading} <header - class="bg-gradient-to-r {$colorTheme} h-[175px] w-full relative bg-cover mb-20" + class="bg-gradient-to-r {$colorTheme} dark:!from-violet-600 dark:!to-swapee-purple h-[175px] w-full relative bg-cover mb-20" style:background-image={bg} > - <nav class="flex justify-end items-center space-x-4 p-5"> + <nav class="flex justify-end items-center gap-x-2 xs:gap-x-4 p-5"> {#if user} <a href={`/${user.username}`}> <button - class="bg-white p-2 rounded-full w-12 h-12 md:w-16 md:h-16 drop-shadow-xl border border-black/10 {$page + class="bg-white dark:bg-black p-2 rounded-full w-12 h-12 md:w-16 md:h-16 drop-shadow-xl border border-black/10 {$page .url.pathname === `/${user.username}` ? 'opacity-100' : 'opacity-70 hover:opacity-80'}" - ><Icon icon="home" style="mx-auto w-6 md:w-8" /> + ><Icon icon="home" style="mx-auto w-6 md:w-8 dark:invert" /> + </button> + </a> + <a href={`/${user.username}/buy`}> + <button + class="bg-white dark:bg-black p-2 rounded-full w-12 h-12 md:w-16 md:h-16 drop-shadow-xl border border-black/10 {$page + .url.pathname === `/${user.username}/buy` + ? 'opacity-100' + : 'opacity-70 hover:opacity-80'}" + ><Icon icon="shop" style="mx-auto w-6 md:w-8 dark:invert" /> </button> </a> <a href={`/${user.username}/receive`}> <button - class="bg-white p-2 rounded-full w-12 h-12 md:w-16 md:h-16 drop-shadow-xl border border-black/10 {$page + class="bg-white dark:bg-black p-2 rounded-full w-12 h-12 md:w-16 md:h-16 drop-shadow-xl border border-black/10 {$page .url.pathname === `/${user.username}/receive` ? 'opacity-100' : 'opacity-70 hover:opacity-80'}" - ><Icon icon="numpad" style="mx-auto w-6 md:w-8" /> + ><Icon icon="numpad" style="mx-auto w-6 md:w-8 dark:invert" /> </button> </a> <a href={`/${user.username}/payments`}> <button - class="bg-white p-2 rounded-full w-12 h-12 md:w-16 md:h-16 drop-shadow-xl border border-black/10 {$page + class="bg-white dark:bg-black p-2 rounded-full w-12 h-12 md:w-16 md:h-16 drop-shadow-xl border border-black/10 {$page .url.pathname === `/${user.username}/payments` ? 'opacity-100' : 'opacity-70 hover:opacity-80'} relative" - ><Icon icon="clock" style="mx-auto w-6 md:w-8" /> + ><Icon icon="clock" style="mx-auto w-6 md:w-8 dark:invert" /> {#if $newPayment} <span class="absolute top-0 right-0"> <span class="flex h-3 w-3"> @@ -87,17 +96,17 @@ </a> <a href={`/send`}> <button - class="bg-white p-2 rounded-full w-12 h-12 md:w-16 md:h-16 drop-shadow-xl border border-black/10 {$page + class="bg-white dark:bg-black p-2 rounded-full w-12 h-12 md:w-16 md:h-16 drop-shadow-xl border border-black/10 {$page .url.pathname === `/send` ? 'opacity-100' : 'opacity-70 hover:opacity-80'}" - ><Icon icon="send" style="mx-auto w-6 md:w-8" /> + ><Icon icon="send" style="mx-auto w-6 md:w-8 dark:invert" /> </button> </a> <div class="relative"> <OutClick on:outclick={() => (showMenu = false)}> <button - class="bg-white p-2 rounded-full w-12 h-12 md:w-16 md:h-16 drop-shadow-xl border border-black/10 {$page + class="bg-white dark:bg-black p-2 rounded-full w-12 h-12 md:w-16 md:h-16 drop-shadow-xl border border-black/10 {$page .url.pathname === `/${user.username}` || $page.url.pathname === `/${user.username}/settings` || $page.url.pathname === `/support` @@ -106,36 +115,37 @@ showMenu ? 'opacity-80' : '' }`}" on:click={() => (showMenu = !showMenu)} - ><Icon icon="menu" style="mx-auto w-6 md:w-8" /> + ><Icon icon="menu" style="mx-auto w-6 md:w-8 dark:invert" /> </button> <div class="{showMenu ? 'block' - : 'hidden'} absolute top-14 right-0 bg-white rounded-3xl p-8 shadow-xl z-50" + : 'hidden'} absolute top-14 right-0 bg-white dark:bg-black dark:border-2 dark:border-gray-50 rounded-3xl p-8 shadow-xl z-50" > <ul class="space-y-5 w-48"> {#each menuButtons as { href, icon, key }} <li> <a {href} data-sveltekit-prefetch="off"> <button - class="flex justify-center items-center font-semibold hover:opacity-80" - ><Icon {icon} style="mr-2 w-6 md:w-8" /> {$t(key)} + class="flex justify-center items-center font-semibold hover:opacity-80 dark:hover:opacity-70" + ><Icon {icon} style="mr-2 w-6 md:w-8 dark:invert" /> {$t(key)} </button> </a> </li> {/each} </ul> - <hr class="my-4" /> - <a href="/" - ><img src="/images/logo.svg" alt="Swapee" class="w-32" /></a - > + <hr class="my-4 dark:border-white" /> + <a href="/"> + <img src="/images/logo.svg" alt="Swapee" class="w-32 dark:hidden" /> + <img src="/images/logo-white.png" alt="Swapee" class="w-32 hidden dark:block" /> + </a> </div> </OutClick> </div> {:else} <a href={`/login?redirect=${$page.url.pathname}`}> - <button class="bg-white px-5 py-2 rounded-xl font-semibold text-sm" + <button class="bg-white dark:bg-black px-5 py-2 rounded-xl font-semibold text-sm" >{$t("nav.signIn")}</button > </a> diff --git a/src/components/Balance.svelte b/src/components/Balance.svelte index 98a04ef6..d72f10e6 100644 --- a/src/components/Balance.svelte +++ b/src/components/Balance.svelte @@ -21,13 +21,13 @@ {:else} <div class="text-5xl font-bold tabular-nums"> {#if isNaN(rate)} - <div class="text-gray-200">—</div> + <div class="text-gray-200 ">—</div> {:else} {f((user.balance * rate) / sats, user.currency)} {/if} </div> - <div class="text-secondary text-2xl"> + <div class="text-secondary dark:text-gray-300 text-2xl"> ⚡️{s(user.balance)} </div> {/if} diff --git a/src/components/Code.svelte b/src/components/Code.svelte index c8c1058a..9d54cc7b 100644 --- a/src/components/Code.svelte +++ b/src/components/Code.svelte @@ -6,7 +6,7 @@ </script> <div - class="bg-black text-white rounded-lg p-4 flex gap-4 whitespace-pre-wrap font-mono" + class="bg-stone-900 dark:bg-stone-800 text-white rounded-lg p-4 px-5 flex gap-4 whitespace-pre-wrap font-mono shadow-inner shadow-stone-950 dark:shadow-stone-900" > <div class="overflow-x-scroll max-w-full scrollbar-hide"> <div class="break-all min-w-[800px]">{samples[sample]}</div> diff --git a/src/components/Footer.svelte b/src/components/Footer.svelte index 92fb23c6..12977900 100644 --- a/src/components/Footer.svelte +++ b/src/components/Footer.svelte @@ -14,62 +14,50 @@ { url: "/support", titleID: "support" }, ]; </script> +<footer class="pt-16 bg-black"> + <div class="max-w-[1296px] mx-auto px-8"> + <!-- footer_top --> + <div class="footer_top pb-4"> + <div class="flex-col md:flex-row flex md:items-center justify-between"> + <div class="flex-1 mb-12 sm:mb-5"> + <a href="#" class="footer_logo"><img src="images/footer-logo.png" alt="" /></a> + <p class="text-gray-200 mt-10">Copyright © 2023. Swapee.me</p> + <p class="text-gray-200 mt-3">All rights reserved.</p> + <a href="#" class="btn_language inline-block mt-6 font-bold !text-white hover:!text-black">English</a> + </div> + <div + class="flex-1 footer_top_right flex items-center justify-start md:justify-center " + > + <div class="flex max-sm:flex-col md:justify-end gap-x-6"> + <div class="flex-1 xl:mb-0 mb-4 md:pr-0 sm:pr-5"> + <h6 class="!text-white/80 mb-0">Business enquiries</h6> + <a href="mailto:[email protected]">[email protected]</a> + </div> + <div class="flex-1 xs:pr-5 mb-4 md:pr-0 sm:pr-5"> + <h6 class="!text-white/80 mb-0">Support enquiries</h6> + <a href="mailto:[email protected]">[email protected]</a> + </div> + </div> + </div> + </div> -<footer - class="space-y-10 md:space-y-0 text-xl block md:flex justify-around mb-20" -> - <div class="space-y-5"> - <div class="text-center w-full"> - <a href="/"><Icon icon="logo" style="w-48 mx-auto md:mx-0" /></a> - </div> - <div class="flex gap-2 justify-center sm:hidden"> - <div> - <a href="/register"> - <button - class="bg-black text-white border rounded-full px-4 py-2 font-bold hover:opacity-80 text-lg" - > - {$t("nav.startInSeconds")} - </button> - </a> - </div> - </div> - <div class="w-full flex"> - <div class="mx-auto"> - <LocaleSelector - style="p-2 text-center hover:opacity-80 cursor-pointer border rounded-full" - /> - </div> - </div> - </div> - - <div class="text-center md:text-left"> - <p class="font-semibold">{$t("footer.followUs")}</p> - <ul class="mt-5 text-secondary space-y-3 font-medium"> - {#each followLinks as link} - <li> - <a - href={link.url} - target="_blank" - rel="noreferrer" - class="hover:opacity-80">{$t("footer." + link.titleID)}</a - > - </li> - {/each} - </ul> - </div> - - <div class="text-center md:text-left"> - <p class="font-semibold">{$t("footer.company")}</p> - <ul class="mt-5 text-secondary space-y-3"> - {#each companyLinks as link} - <li> - <a href={link.url} class="hover:opacity-80" - >{$t("footer." + link.titleID)}</a - > - </li> - {/each} - </ul> - </div> - - <Icon icon="shield" style="mx-auto md:mx-0" /> + <!-- footer_bottom --> + <div class="footer_bottom pt-4 pb-2"> + <ul class="list-unstyled mb-0 ps-0"> + <li class="pb-3 "> + <a href="/docs" class="!text-white/80 opacity-100 hover:!text-swapee-purple/100 font-semibold">Documentation</a> + </li> + <li class="pb-3"> + <a href="/privacy" class="!text-white/80 opacity-100 hover:!text-swapee-purple/100 font-semibold">Privacy Policy</a> + </li> + <li class="pb-3"> + <a href="/support" class="!text-white/80 opacity-100 hover:!text-swapee-purple/100 font-semibold">Support</a> + </li> + <li class="pb-3"> + <a href="/sitemap" class="!text-white/80 opacity-100 hover:!text-swapee-purple/100 font-semibold">Sitemap</a> + </li> + </ul> + </div> + </div> + </div> </footer> diff --git a/src/components/LandingHeader.svelte b/src/components/LandingHeader.svelte index 009ab063..e0a2aad0 100644 --- a/src/components/LandingHeader.svelte +++ b/src/components/LandingHeader.svelte @@ -19,13 +19,14 @@ </script> <header - class="w-full lg:w-5/6 py-5 mx-auto fixed md:sticky z-10 top-0 bg-white/90" + class="w-full container px-10 lg:px-40 md:pb-5 pt-5 mx-auto fixed md:sticky z-10 top-0 bg-white/80 dark:bg-black/80 backdrop-blur-sm" bind:this={header} > - <nav class="block xl:flex flex-wrap justify-between items-center"> + <nav class="reltive flex flex-wrap justify-between items-center max-md:pb-4"> <div class="flex justify-start md:justify-center items-center md:space-x-10"> - <a href="/" on:click={() => scroll(header)}> - <img src="images/logo.png" class="max-w-[140px]" /> + <a href="/" on:click={() => scroll(header)} class=""> + <img src="images/logo.png" class="max-w-[140px] dark:hidden" alt="swapee logo" /> + <img src="images/logo-white.png" class="max-w-[140px] hidden dark:inline-block" alt="swapee logo" /> </a> </div> @@ -46,24 +47,24 @@ {/if} {#if user} <button - class="border rounded-full px-6 py-2 font-bold" + class="dark:!bg-black dark:!text-white border-black dark:!border-white !border-2 !font-bold px-6 py-2 rounded-full" on:click={() => goto(`/${user.username}`)} - >Home + >Home </button> <button - class="bg-black text-white border rounded-full px-6 py-2 font-bold" + class="bg-black dark:!bg-white dark:!text-black !text-white border-2 border-black rounded-full px-6 py-2 font-bold" on:click={() => goto("/logout")} > {$t("nav.signOut")} </button> {:else} <button - class="border rounded-full px-6 py-2 font-bold hover:opacity-80" + class="dark:!bg-black dark:!text-white border-black dark:!border-white !border-2 !font-bold px-6 py-2 rounded-full hover:opacity-80" on:click={() => goto("/register")} >{$t("nav.startInSeconds")} </button> <button - class="bg-black text-white border rounded-full px-6 py-2 font-bold hover:opacity-80" + class="bg-black dark:!bg-white dark:!text-black !text-white border-2 border-black rounded-full px-6 py-2 font-bold hover:opacity-80" on:click={() => goto("/login")} > {$t("nav.signIn")} @@ -73,46 +74,46 @@ <!-- mobile nav --> <button - class="block md:hidden absolute top-[34.5px] right-10 z" + class="scale-125 z-50 md:hidden" on:click={() => (showMobileMenu = !showMobileMenu)} - ><Icon icon={!showMobileMenu ? "menu" : "close"} /> + ><Icon icon={!showMobileMenu ? "menu" : "close"} style="dark:invert" /> </button> <div class="container w-full px-10 md:hidden absolute top-0 {showMobileMenu ? 'right-0' - : 'right-[-100%]'} transition-all ease-in-out duration-300 h-[100vh] w-full bg-white" + : 'right-[-100%]'} transition-all ease-in-out duration-300 h-[100vh] w-full bg-white dark:bg-black" > <div class="space-y-8 mt-24 font-bold text-xl"> - <button on:click={() => mobileMenuButtonClick(howItWorks)} class="block" + <button on:click={() => mobileMenuButtonClick(howItWorks)} class="block dark:!text-gray-200" >{$t("howItWorks.header")}</button > - <button on:click={() => mobileMenuButtonClick(faq)} class="block" + <button on:click={() => mobileMenuButtonClick(faq)} class="block dark:!text-gray-200" >{$t("faq.header")}</button > - <button on:click={() => mobileMenuButtonClick(about)} class="block" + <button on:click={() => mobileMenuButtonClick(about)} class="block dark:!text-gray-200" >{$t("about.header")}</button > {#if !user} <button - class="border rounded-full px-6 py-2 font-bold block w-full" + class="dark:!bg-black dark:!text-white border-black dark:!border-white !border-2 !font-bold px-6 py-2 rounded-full w-full" on:click={() => goto("/register")} >{$t("nav.startInSeconds")} </button> <button - class="bg-black text-white border rounded-full px-6 py-2 font-bold block w-full" + class="bg-black dark:!bg-white dark:!text-black !text-white border-2 border-black rounded-full px-6 py-2 font-bold w-full" on:click={() => goto("/login")} > {$t("nav.signIn")} </button> {:else} <button - class="border rounded-full px-6 py-2 font-bold block" + class="dark:!bg-black dark:!text-white border-black dark:!border-white !border-2 !font-bold px-6 py-2 rounded-full" on:click={() => goto(`/${user.username}`)} >{$t("nav.account")} </button> <button - class="bg-black text-white border rounded-full px-6 py-2 font-bold block" + class="bg-black dark:!bg-white dark:!text-black !text-white border-2 border-black rounded-full px-6 py-2 font-bold w-full" on:click={() => goto("/logout")} > {$t("nav.signOut")} @@ -124,6 +125,7 @@ </header> <style> + @import '../../static/style.css'; .z { z-index: 100; } diff --git a/src/components/Numpad.svelte b/src/components/Numpad.svelte index 901d11ba..aa109f7e 100644 --- a/src/components/Numpad.svelte +++ b/src/components/Numpad.svelte @@ -183,7 +183,7 @@ <div class="text-5xl md:text-6xl font-semibold tracking-widest flex justify-center" > - <div class="my-auto" class:text-5xl={!fiat}> + <div class="my-auto font-bebasNeue tracking-[0.2rem]" class:text-5xl={!fiat}> {fiat ? symbol : "⚡️"} </div> <div @@ -194,11 +194,11 @@ on:blur={blur} on:input={input} on:keydown={keydown} - class="outline-none my-auto" + class="outline-none my-auto font-bebasNeue tracking-[0.4rem] mt-2" /> </div> <div class="mt-2"> - <span class="text-secondary mr-1" + <span class="text-secondary dark:text-gray-300 mr-1" >{fiat ? sat(amount) : f(amountFiat, currency)}</span > <button @@ -213,7 +213,7 @@ : 0; } fiat = !fiat; - }}><Icon icon="swap" style="inline hover:opacity-80" /></button + }}><Icon icon="swap" style="inline hover:opacity-80 dark:invert" /></button > </div> </div> @@ -223,7 +223,7 @@ {#if value === arrow} <button type="button" - class="bg-gray-100 rounded-xl py-4 px-8 font-semibold active:bg-black active:flex justify-center items-center hover:opacity-80" + class="bg-gray-100 dark:bg-stone-800 rounded-xl py-4 px-8 font-semibold active:bg-black dark:active:bg-stone-900 active:flex justify-center items-center hover:opacity-80" on:click={() => handleInput(value)} > <Left /> @@ -231,7 +231,7 @@ {:else} <button type="button" - class="bg-gray-100 rounded-xl py-4 px-8 font-semibold active:bg-black active:text-white hover:opacity-80" + class="bg-gray-100 dark:bg-stone-800 rounded-xl py-4 px-8 font-semibold active:bg-black dark:active:bg-stone-900 active:text-white hover:opacity-80" on:click={() => handleInput(value)}>{value}</button > {/if} diff --git a/src/components/Password.svelte b/src/components/Password.svelte index da65d718..81714904 100644 --- a/src/components/Password.svelte +++ b/src/components/Password.svelte @@ -23,10 +23,10 @@ </script> <div - class="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-20" + class="fixed inset-0 bg-gray-600 dark:bg-stone-950 dark:bg-opacity-90 bg-opacity-50 overflow-y-auto h-full w-full z-20" > <div - class="relative top-1/3 mx-auto p-5 border w-96 shadow-lg rounded-md bg-white space-y-5" + class="relative top-1/3 mx-auto p-5 border w-96 shadow-lg rounded-md bg-white dark:bg-stone-800 dark:border-0 space-y-5" > <h1 class="text-center text-2xl font-semibold"> Please enter your password @@ -38,7 +38,7 @@ name="password" type="text" required - class="bg-primary" + class="bg-primary dark:bg-stone-700 dark:border-gray-50" bind:value={password} autocapitalize="none" use:focus @@ -48,7 +48,7 @@ name="password" type="password" required - class="bg-primary" + class="bg-primary dark:bg-stone-700 dark:border-gray-50" bind:value={password} autocapitalize="none" use:focus @@ -57,7 +57,7 @@ <button type="button" on:click={() => (revealPassword = !revealPassword)} - class="absolute right-5 top-6" + class="absolute right-5 dark:invert {revealPassword ? 'top-[18px]' : 'top-[16px]'}" > <Icon icon={revealPassword ? "eye" : "eye-off"} /> </button> @@ -65,7 +65,7 @@ <div class="w-full flex"> <button type="button" - class="border-2 border-black rounded-xl font-semibold mx-auto py-3 w-40 hover:opacity-80 mx-auto" + class="border-2 border-black dark:border-gray-50 dark:text-gray-50 rounded-xl font-semibold py-3 w-40 hover:opacity-80 mx-auto" on:click={cancel} on:keydown={cancel} > @@ -73,7 +73,7 @@ </button> <button type="submit" - class="border-2 border-black rounded-xl font-semibold mx-auto py-3 w-40 hover:opacity-80 mx-auto" + class="border-2 border-black dark:border-gray-50 bg-black text-white dark:bg-gray-50 dark:text-black rounded-xl font-semibold py-3 w-40 hover:opacity-80 mx-auto" > <div class="my-auto">Submit</div> </button> diff --git a/src/components/Pin.svelte b/src/components/Pin.svelte index 9938f9a1..58a669e8 100644 --- a/src/components/Pin.svelte +++ b/src/components/Pin.svelte @@ -43,16 +43,16 @@ {#if loaded} <div - class="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50" + class="fixed inset-0 bg-gray-600 dark:bg-stone-950 dark:bg-opacity-90 bg-opacity-50 overflow-y-auto h-full w-full z-50" > <div - class="relative top-40 mx-auto p-5 border w-96 shadow-lg rounded-md bg-white space-y-5" + class="relative top-40 mx-auto p-5 border w-96 shadow-lg rounded-lg bg-white dark:bg-stone-800 dark:border-0 space-y-5" > <h1 class="text-center text-2xl font-semibold">{title}</h1> <Pinpad bind:v={p} {cancel} /> <div class="w-full flex"> <button - class="border-2 border-black rounded-xl font-semibold mx-auto py-3 w-40 hover:opacity-80 mx-auto" + class="border-2 border-black dark:border-gray-50 dark:text-gray-50 rounded-xl font-semibold mx-auto py-3 w-40 hover:opacity-80" on:click|preventDefault={cancel} > <div class="my-auto">Cancel</div> diff --git a/src/components/Pinpad.svelte b/src/components/Pinpad.svelte index 641ddb2b..1dc20366 100644 --- a/src/components/Pinpad.svelte +++ b/src/components/Pinpad.svelte @@ -45,14 +45,14 @@ use:focus bind:value={v} type="password" - class="outline-none border-0 text-center py-0" + class="outline-none border-0 text-center py-0 dark:bg-stone-800 dark:text-white" pattern="[0-9]+" /> {:else} <input on:keydown={validate} bind:value={v} - class="outline-none border-0 text-center py-0" + class="outline-none border-0 text-center py-0 dark:bg-stone-800 dark:text-white" type="text" pattern="[0-9]+" /> @@ -60,18 +60,18 @@ <button type="button" on:click={() => (hide = !hide)} - class="absolute -right-5 top-5" + class="absolute -right-5 dark:invert {hide ? 'top-5' : 'top-[22px]'}" > <Icon icon={hide ? "eye-off" : "eye"} style="w-8" /> </button> </div> - <div class="grid grid-cols-3 gap-2 w-[300px] mx-auto grayscale"> + <div class="grid grid-cols-3 gap-2 w-[300px] mx-auto"> {#each numPad as value} {#if value === arrow} <button type="button" - class="bg-primary rounded-xl py-4 px-8 font-semibold active:bg-black active:text-white flex justify-center items-center hover:opacity-80" + class="bg-primary dark:bg-stone-700 rounded-xl py-4 px-8 font-semibold dark:text-gray-50 active:bg-black active:text-white flex justify-center items-center hover:opacity-80" on:click={() => handleInput(value)} > <Left /> @@ -79,7 +79,7 @@ {:else} <button type="button" - class="bg-primary rounded-xl py-4 px-8 font-semibold active:bg-black active:text-white hover:opacity-80" + class="bg-primary dark:bg-stone-700 rounded-xl py-4 px-8 font-semibold dark:text-gray-50 active:bg-black dark:active:bg-stone-900 active:text-white hover:opacity-80" on:click={() => handleInput(value)}>{value}</button > {/if} diff --git a/src/components/Toggle.svelte b/src/components/Toggle.svelte index 2f92837d..1d34ccd6 100644 --- a/src/components/Toggle.svelte +++ b/src/components/Toggle.svelte @@ -3,7 +3,9 @@ export let value; </script> -<label for={id} class="inline-flex relative items-center mr-5 cursor-pointer"> +<!-- svelte-ignore a11y-click-events-have-key-events --> +<!-- svelte-ignore a11y-no-noninteractive-element-interactions --> +<label for={id} class="inline-flex relative items-center mr-5 cursor-pointer" on:click> <input type="checkbox" bind:checked={value} @@ -12,6 +14,6 @@ class="sr-only peer" /> <div - class="w-11 h-6 bg-gray-200 rounded-full peer dark:bg-gray-700 peer-focus:ring-4 peer-focus:ring-gray-300 dark:peer-focus:ring-gray-800 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-0.5 after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-green-500" + class="w-11 h-6 bg-gray-200 rounded-full peer dark:bg-stone-800 peer-focus:ring-4 peer-focus:ring-gray-300 dark:peer-focus:ring-gray-800 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-0.5 after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-green-500" /> </label> diff --git a/src/components/buttons/ThemeToggle.svelte b/src/components/buttons/ThemeToggle.svelte new file mode 100644 index 00000000..7b9a06e4 --- /dev/null +++ b/src/components/buttons/ThemeToggle.svelte @@ -0,0 +1,28 @@ +<!-- <button {...$$restProps}>toggle</button> --> +<button + class="text-white dark:!text-black hover:bg-gray-100 dark:!hover:bg-gray-700 focus:outline-none focus:ring-4 focus:ring-gray-200 border-2 border-gray-600 bg-black dark:!bg-white dark:!border-gray-300 dark:!focus:ring-gray-700 rounded-full text-sm p-2.5 transition-all" + {...$$restProps} +> + <svg + class="w-5 h-5 dark:hidden" + fill="currentColor" + viewBox="0 0 20 20" + xmlns="http://www.w3.org/2000/svg" + > + <path + d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z" + ></path> + </svg> + <svg + class="w-5 h-5 hidden dark:!block" + fill="currentColor" + viewBox="0 0 20 20" + xmlns="http://www.w3.org/2000/svg" + > + <path + d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z" + fill-rule="evenodd" + clip-rule="evenodd" + ></path> + </svg> +</button>
\ No newline at end of file diff --git a/src/hooks.server.js b/src/hooks.server.js new file mode 100644 index 00000000..dca44977 --- /dev/null +++ b/src/hooks.server.js @@ -0,0 +1,29 @@ + +export const handle = (async ({ event, resolve }) => { + let theme = "dark"; + + const newTheme = event.url.searchParams.get("theme"); + const cookieTheme = event.cookies.get("colortheme"); + + if (newTheme) { + theme = newTheme; + } else if (cookieTheme) { + theme = cookieTheme; + } + + if (theme) { + return await resolve(event, { + transformPageChunk: ({ html }) => { + const modifiedHtml = html.replace(/<html[^>]*>/, (match) => { + // Ensure the class attribute exists or add it if missing + return match.includes('class="') + ? match.replace(/class="[^"]*"/, `class="${theme}"`) + : match.replace('>', ` class="${theme}">`); + }); + return modifiedHtml; + } + }); + } + + return await resolve(event); +})
\ No newline at end of file diff --git a/src/lib/shadcn/components/ui/accordion/accordion-content.svelte b/src/lib/shadcn/components/ui/accordion/accordion-content.svelte new file mode 100644 index 00000000..14328e88 --- /dev/null +++ b/src/lib/shadcn/components/ui/accordion/accordion-content.svelte @@ -0,0 +1,22 @@ +<script> + import { Accordion as AccordionPrimitive } from "bits-ui"; + import { cn } from "$lib/shadcn/utils"; + import { slide } from "svelte/transition"; + let className = undefined; + export let transition = slide; + export let transitionConfig = { + duration: 200, + }; + export { className as class }; +</script> + +<AccordionPrimitive.Content + class={cn("overflow-hidden text-sm transition-all", className)} + {transition} + {transitionConfig} + {...$$restProps} +> + <div class="pb-4 pt-0"> + <slot /> + </div> +</AccordionPrimitive.Content> diff --git a/src/lib/shadcn/components/ui/accordion/accordion-item.svelte b/src/lib/shadcn/components/ui/accordion/accordion-item.svelte new file mode 100644 index 00000000..b0887d7e --- /dev/null +++ b/src/lib/shadcn/components/ui/accordion/accordion-item.svelte @@ -0,0 +1,11 @@ +<script> + import { Accordion as AccordionPrimitive } from "bits-ui"; + import { cn } from "$lib/shadcn/utils"; + let className = undefined; + export let value; + export { className as class }; +</script> + +<AccordionPrimitive.Item {value} class={cn("border-b", className)} {...$$restProps}> + <slot /> +</AccordionPrimitive.Item> diff --git a/src/lib/shadcn/components/ui/accordion/accordion-trigger.svelte b/src/lib/shadcn/components/ui/accordion/accordion-trigger.svelte new file mode 100644 index 00000000..8acf4675 --- /dev/null +++ b/src/lib/shadcn/components/ui/accordion/accordion-trigger.svelte @@ -0,0 +1,22 @@ +<script> + import { Accordion as AccordionPrimitive } from "bits-ui"; + import { ChevronDown } from "lucide-svelte"; + import { cn } from "$lib/shadcn/utils"; + let className = undefined; + export let level = 3; + export { className as class }; +</script> + +<AccordionPrimitive.Header {level} class="flex"> + <AccordionPrimitive.Trigger + class={cn( + "flex flex-1 items-center justify-between py-2 font-medium transition-all [&[data-state=open]>svg]:rotate-180", + className + )} + {...$$restProps} + on:click + > + <slot /> + <ChevronDown class="h-4 w-4 transition-transform duration-200" /> + </AccordionPrimitive.Trigger> +</AccordionPrimitive.Header> diff --git a/src/lib/shadcn/components/ui/accordion/index.js b/src/lib/shadcn/components/ui/accordion/index.js new file mode 100644 index 00000000..d75ea273 --- /dev/null +++ b/src/lib/shadcn/components/ui/accordion/index.js @@ -0,0 +1,16 @@ +import { Accordion as AccordionPrimitive } from "bits-ui"; +import Content from "./accordion-content.svelte"; +import Item from "./accordion-item.svelte"; +import Trigger from "./accordion-trigger.svelte"; +const Root = AccordionPrimitive.Root; +export { + Root, + Content, + Item, + Trigger, + // + Root as Accordion, + Content as AccordionContent, + Item as AccordionItem, + Trigger as AccordionTrigger, +}; diff --git a/src/lib/shadcn/components/ui/button/button.svelte b/src/lib/shadcn/components/ui/button/button.svelte new file mode 100644 index 00000000..775b9f09 --- /dev/null +++ b/src/lib/shadcn/components/ui/button/button.svelte @@ -0,0 +1,21 @@ +<script> + import { Button as ButtonPrimitive } from "bits-ui"; + import { cn } from "$lib/shadcn/utils"; + import { buttonVariants } from "."; + let className = undefined; + export let variant = "default"; + export let size = "default"; + export let builders = []; + export { className as class }; +</script> + +<ButtonPrimitive.Root + {builders} + class={cn(buttonVariants({ variant, size, className }))} + type="button" + {...$$restProps} + on:click + on:keydown +> + <slot /> +</ButtonPrimitive.Root> diff --git a/src/lib/shadcn/components/ui/button/index.js b/src/lib/shadcn/components/ui/button/index.js new file mode 100644 index 00000000..96d93665 --- /dev/null +++ b/src/lib/shadcn/components/ui/button/index.js @@ -0,0 +1,32 @@ +import Root from "./button.svelte"; +import { tv } from "tailwind-variants"; +const buttonVariants = tv({ + base: "inline-flex items-center justify-center rounded-md text-sm font-medium whitespace-nowrap ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", + variants: { + variant: { + default: "bg-primary text-primary-foreground hover:bg-primary/90", + destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90", + outline: + "border border-input bg-background hover:bg-accent hover:text-accent-foreground", + secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80", + ghost: "hover:bg-accent hover:text-accent-foreground", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-10 px-4 py-2", + sm: "h-9 rounded-md px-3", + lg: "h-11 rounded-md px-8", + icon: "h-10 w-10", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, +}); +export { + Root, + // + Root as Button, + buttonVariants, +}; diff --git a/src/lib/shadcn/components/ui/separator/index.js b/src/lib/shadcn/components/ui/separator/index.js new file mode 100644 index 00000000..073c5c4c --- /dev/null +++ b/src/lib/shadcn/components/ui/separator/index.js @@ -0,0 +1,6 @@ +import Root from "./separator.svelte"; +export { + Root, + // + Root as Separator, +}; diff --git a/src/lib/shadcn/components/ui/separator/separator.svelte b/src/lib/shadcn/components/ui/separator/separator.svelte new file mode 100644 index 00000000..b07c93ea --- /dev/null +++ b/src/lib/shadcn/components/ui/separator/separator.svelte @@ -0,0 +1,19 @@ +<script> + import { Separator as SeparatorPrimitive } from "bits-ui"; + import { cn } from "$lib/shadcn/utils"; + let className = undefined; + export let orientation = "horizontal"; + export let decorative = undefined; + export { className as class }; +</script> + +<SeparatorPrimitive.Root + class={cn( + "shrink-0 bg-border", + orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]", + className + )} + {orientation} + {decorative} + {...$$restProps} +/> diff --git a/src/lib/shadcn/components/ui/sheet/index.js b/src/lib/shadcn/components/ui/sheet/index.js new file mode 100644 index 00000000..c892767c --- /dev/null +++ b/src/lib/shadcn/components/ui/sheet/index.js @@ -0,0 +1,99 @@ +import { Dialog as SheetPrimitive } from "bits-ui"; +import { tv } from "tailwind-variants"; +import Portal from "./sheet-portal.svelte"; +import Overlay from "./sheet-overlay.svelte"; +import Content from "./sheet-content.svelte"; +import Header from "./sheet-header.svelte"; +import Footer from "./sheet-footer.svelte"; +import Title from "./sheet-title.svelte"; +import Description from "./sheet-description.svelte"; +const Root = SheetPrimitive.Root; +const Close = SheetPrimitive.Close; +const Trigger = SheetPrimitive.Trigger; +export { + Root, + Close, + Trigger, + Portal, + Overlay, + Content, + Header, + Footer, + Title, + Description, + // + Root as Sheet, + Close as SheetClose, + Trigger as SheetTrigger, + Portal as SheetPortal, + Overlay as SheetOverlay, + Content as SheetContent, + Header as SheetHeader, + Footer as SheetFooter, + Title as SheetTitle, + Description as SheetDescription, +}; +export const sheetVariants = tv({ + base: "fixed z-50 gap-4 bg-background p-6 shadow-lg", + variants: { + side: { + top: "inset-x-0 top-0 border-b", + bottom: "inset-x-0 bottom-0 border-t", + left: "inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm", + right: "inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm", + }, + }, + defaultVariants: { + side: "right", + }, +}); +export const sheetTransitions = { + top: { + in: { + y: "-100%", + duration: 500, + opacity: 1, + }, + out: { + y: "-100%", + duration: 300, + opacity: 1, + }, + }, + bottom: { + in: { + y: "100%", + duration: 500, + opacity: 1, + }, + out: { + y: "100%", + duration: 300, + opacity: 1, + }, + }, + left: { + in: { + x: "-100%", + duration: 500, + opacity: 1, + }, + out: { + x: "-100%", + duration: 300, + opacity: 1, + }, + }, + right: { + in: { + x: "100%", + duration: 500, + opacity: 1, + }, + out: { + x: "100%", + duration: 300, + opacity: 1, + }, + }, +}; diff --git a/src/lib/shadcn/components/ui/sheet/sheet-content.svelte b/src/lib/shadcn/components/ui/sheet/sheet-content.svelte new file mode 100644 index 00000000..8e7a0ffd --- /dev/null +++ b/src/lib/shadcn/components/ui/sheet/sheet-content.svelte @@ -0,0 +1,34 @@ +<script> + import { Dialog as SheetPrimitive } from "bits-ui"; + import X from "lucide-svelte/icons/x"; + import { SheetOverlay, SheetPortal, sheetTransitions, sheetVariants } from "."; + import { cn } from "$lib/shadcn/utils"; + import { fly } from "svelte/transition"; + let className = undefined; + export let side = "right"; + export { className as class }; + export let inTransition = fly; + export let inTransitionConfig = sheetTransitions[side ? side : "right"]["in"]; + export let outTransition = fly; + export let outTransitionConfig = sheetTransitions[side ? side : "right"]["out"]; +</script> + +<SheetPortal> + <SheetOverlay /> + <SheetPrimitive.Content + {inTransition} + {inTransitionConfig} + {outTransition} + {outTransitionConfig} + class={cn(sheetVariants({ side }), className)} + {...$$restProps} + > + <slot /> + <SheetPrimitive.Close + class="absolute right-4 top-4 rounded-sm opacity-100 ring-offset-background hover:bg-swapee-purple transition-all focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-black dark:data-[state=open]:bg-white" + > + <X class="h-8 w-8" /> + <span class="sr-only">Close</span> + </SheetPrimitive.Close> + </SheetPrimitive.Content> +</SheetPortal> diff --git a/src/lib/shadcn/components/ui/sheet/sheet-description.svelte b/src/lib/shadcn/components/ui/sheet/sheet-description.svelte new file mode 100644 index 00000000..9f75b9f4 --- /dev/null +++ b/src/lib/shadcn/components/ui/sheet/sheet-description.svelte @@ -0,0 +1,10 @@ +<script> + import { Dialog as SheetPrimitive } from "bits-ui"; + import { cn } from "$lib/shadcn/utils"; + let className = undefined; + export { className as class }; +</script> + +<SheetPrimitive.Description class={cn("text-sm text-muted-foreground", className)} {...$$restProps}> + <slot /> +</SheetPrimitive.Description> diff --git a/src/lib/shadcn/components/ui/sheet/sheet-footer.svelte b/src/lib/shadcn/components/ui/sheet/sheet-footer.svelte new file mode 100644 index 00000000..3a958ac9 --- /dev/null +++ b/src/lib/shadcn/components/ui/sheet/sheet-footer.svelte @@ -0,0 +1,12 @@ +<script> + import { cn } from "$lib/shadcn/utils"; + let className = undefined; + export { className as class }; +</script> + +<div + class={cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className)} + {...$$restProps} +> + <slot /> +</div> diff --git a/src/lib/shadcn/components/ui/sheet/sheet-header.svelte b/src/lib/shadcn/components/ui/sheet/sheet-header.svelte new file mode 100644 index 00000000..c6c098a4 --- /dev/null +++ b/src/lib/shadcn/components/ui/sheet/sheet-header.svelte @@ -0,0 +1,9 @@ +<script> + import { cn } from "$lib/shadcn/utils"; + let className = undefined; + export { className as class }; +</script> + +<div class={cn("flex flex-col space-y-2 text-center sm:text-left", className)} {...$$restProps}> + <slot /> +</div> diff --git a/src/lib/shadcn/components/ui/sheet/sheet-overlay.svelte b/src/lib/shadcn/components/ui/sheet/sheet-overlay.svelte new file mode 100644 index 00000000..8f308ce9 --- /dev/null +++ b/src/lib/shadcn/components/ui/sheet/sheet-overlay.svelte @@ -0,0 +1,18 @@ +<script> + import { Dialog as SheetPrimitive } from "bits-ui"; + import { cn } from "$lib/shadcn/utils"; + import { fade } from "svelte/transition"; + let className = undefined; + export let transition = fade; + export let transitionConfig = { + duration: 150, + }; + export { className as class }; +</script> + +<SheetPrimitive.Overlay + {transition} + {transitionConfig} + class={cn("fixed inset-0 z-50 bg-background/80 backdrop-blur-sm ", className)} + {...$$restProps} +/> diff --git a/src/lib/shadcn/components/ui/sheet/sheet-portal.svelte b/src/lib/shadcn/components/ui/sheet/sheet-portal.svelte new file mode 100644 index 00000000..c7384693 --- /dev/null +++ b/src/lib/shadcn/components/ui/sheet/sheet-portal.svelte @@ -0,0 +1,10 @@ +<script> + import { Dialog as SheetPrimitive } from "bits-ui"; + import { cn } from "$lib/shadcn/utils"; + let className = undefined; + export { className as class }; +</script> + +<SheetPrimitive.Portal class={cn(className)} {...$$restProps}> + <slot /> +</SheetPrimitive.Portal> diff --git a/src/lib/shadcn/components/ui/sheet/sheet-title.svelte b/src/lib/shadcn/components/ui/sheet/sheet-title.svelte new file mode 100644 index 00000000..1a285c75 --- /dev/null +++ b/src/lib/shadcn/components/ui/sheet/sheet-title.svelte @@ -0,0 +1,13 @@ +<script> + import { Dialog as SheetPrimitive } from "bits-ui"; + import { cn } from "$lib/shadcn/utils"; + let className = undefined; + export { className as class }; +</script> + +<SheetPrimitive.Title + class={cn("text-lg font-semibold text-foreground", className)} + {...$$restProps} +> + <slot /> +</SheetPrimitive.Title> diff --git a/src/lib/shadcn/components/ui/switch/index.js b/src/lib/shadcn/components/ui/switch/index.js new file mode 100644 index 00000000..7745ca39 --- /dev/null +++ b/src/lib/shadcn/components/ui/switch/index.js @@ -0,0 +1,6 @@ +import Root from "./switch.svelte"; +export { + Root, + // + Root as Switch, +}; diff --git a/src/lib/shadcn/components/ui/switch/switch.svelte b/src/lib/shadcn/components/ui/switch/switch.svelte new file mode 100644 index 00000000..69c08b03 --- /dev/null +++ b/src/lib/shadcn/components/ui/switch/switch.svelte @@ -0,0 +1,22 @@ +<script> + import { Switch as SwitchPrimitive } from "bits-ui"; + import { cn } from "$lib/shadcn/utils"; + let className = undefined; + export let checked = undefined; + export { className as class }; +</script> + +<SwitchPrimitive.Root + bind:checked + class={cn( + "peer inline-flex h-[24px] w-[44px] shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input", + className + )} + {...$$restProps} +> + <SwitchPrimitive.Thumb + class={cn( + "pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0" + )} + /> +</SwitchPrimitive.Root> diff --git a/src/lib/shadcn/utils.js b/src/lib/shadcn/utils.js new file mode 100644 index 00000000..08747b8f --- /dev/null +++ b/src/lib/shadcn/utils.js @@ -0,0 +1,48 @@ +import { clsx } from "clsx"; +import { twMerge } from "tailwind-merge"; +import { cubicOut } from "svelte/easing"; + +export function cn(...inputs) { + return twMerge(clsx(inputs)); +} + +export const flyAndScale = ( + node, + params = { y: -8, x: 0, start: 0.95, duration: 150 } +) => { + const style = getComputedStyle(node); + const transform = style.transform === "none" ? "" : style.transform; + + const scaleConversion = (valueA, scaleA, scaleB) => { + const [minA, maxA] = scaleA; + const [minB, maxB] = scaleB; + + const percentage = (valueA - minA) / (maxA - minA); + const valueB = percentage * (maxB - minB) + minB; + + return valueB; + }; + + const styleToString = (style) => { + return Object.keys(style).reduce((str, key) => { + if (style[key] === undefined) return str; + return str + `${key}:${style[key]};`; + }, ""); + }; + + return { + duration: params.duration ?? 200, + delay: 0, + css: (t) => { + const y = scaleConversion(t, [0, 1], [params.y ?? 5, 0]); + const x = scaleConversion(t, [0, 1], [params.x ?? 0, 0]); + const scale = scaleConversion(t, [0, 1], [params.start ?? 0.95, 1]); + + return styleToString({ + transform: `${transform} translate3d(${x}px, ${y}px, 0) scale(${scale})`, + opacity: t + }); + }, + easing: cubicOut + }; +}; diff --git a/src/lib/utils.js b/src/lib/utils.js index 738413bf..434ca268 100644 --- a/src/lib/utils.js +++ b/src/lib/utils.js @@ -300,4 +300,4 @@ export let isLiquid = (text) => (text.startsWith("ert1q") && text.length === 43) || (text.startsWith("ex1q") && text.length === 42) || text.startsWith("el1qq") || - text.startsWith("lq1qq"); + text.startsWith("lq1qq");
\ No newline at end of file diff --git a/src/locales/en.json b/src/locales/en.json index 1afa0f22..292c669a 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -199,7 +199,7 @@ "scan": "Scan", "paste": "Paste", "next": "Next", - "placeholder": "Paste a bitcoin address, lightning invoice or coinos username" + "placeholder": "Paste a bitcoin address, lightning invoice or Swapee username" }, "settings": { "notifications": "Payment notifications", diff --git a/src/routes/(app)/[username]/(profile)/+layout.svelte b/src/routes/(app)/[username]/(profile)/+layout.svelte index ff7ef7dd..a780f994 100644 --- a/src/routes/(app)/[username]/(profile)/+layout.svelte +++ b/src/routes/(app)/[username]/(profile)/+layout.svelte @@ -75,9 +75,8 @@ }; </script> -<div class="container mx-auto w-full px-4 flex flex-wrap lg:flex-nowrap"> - <div class="hidden lg:block lg:w-[300px]" /> - <div class="lg:w-[300px] lg:absolute space-y-5 left-20 mx-auto max-w-sm"> +<div class="mx-auto w-full px-4 flex flex-col lg:flex-row"> + <div class="lg:w-[300px] space-y-5 mx-auto max-w-sm lg:ml-24"> <div class="flex text-3xl font-bold text-center mx-auto justify-center gap-2" > @@ -152,11 +151,11 @@ <div class="flex justify-center gap-2"> <a href={`/${subject.pubkey}/follows`} ><b>{subject.follows.length}</b> - <span class="text-secondary">{$t("user.following")}</span></a + <span class="text-secondary dark:text-gray-300">{$t("user.following")}</span></a > <a href={`/${subject.pubkey}/followers`} ><b>{subject.followers.length}</b> - <span class="text-secondary">{$t("user.followers")}</span></a + <span class="text-secondary dark:text-gray-300">{$t("user.followers")}</span></a > </div> @@ -242,7 +241,7 @@ </div> <div class="w-full"> - <div class="mx-auto space-y-5 lg:max-w-xl lg:pl-10 xl:max-w-2xl lg:pl-10"> + <div class="mx-auto space-y-5 lg:max-w-xl xl:max-w-2xl lg:pl-10"> <slot /> </div> </div> @@ -250,16 +249,16 @@ {#if currency} <div - class="flex fixed w-full px-4 bg-white py-2 pb-3 bottom-0 bg-opacity-90 tabular-nums" + class="flex fixed w-full px-4 bg-white dark:bg-black py-2 pb-3 bottom-0 bg-opacity-90 tabular-nums" > - <div class="text-secondary flex mr-auto"> + <div class="text-secondary dark:text-gray-300 flex mr-auto"> <div class="flex mr-1"> <div class="my-auto mr-1">1</div> <img src="/images/bitcoin.svg" class="w-5 my-auto" alt="Bitcoin" /> </div> <div>= {f(rates[currency], currency)}</div> </div> - <div class="text-secondary flex ml-auto"> + <div class="text-secondary dark:text-gray-300 flex ml-auto"> <div class="flex"> <div class="mr-1">⚡️{s((1 * sats) / rates[currency])} =</div> <div>{f(1, currency)}</div> diff --git a/src/routes/(app)/[username]/(profile)/+page.svelte b/src/routes/(app)/[username]/(profile)/+page.svelte index 337e80d8..2812100c 100644 --- a/src/routes/(app)/[username]/(profile)/+page.svelte +++ b/src/routes/(app)/[username]/(profile)/+page.svelte @@ -84,8 +84,8 @@ </div> <div class="space-y-8 mt-8"> {#if !user.balance} - <p class="text-secondary text-lg"> - {$t("user.welcome")} + <p class="text-secondary dark:text-gray-300 text-lg max-w-2xl text-center lg:text-start mx-auto"> + {$t("user.welcome")} </p> {/if} @@ -94,10 +94,10 @@ > <a href={`/send`} class="w-full md:w-40"> <button - class="rounded-full border py-3 px-6 font-bold hover:opacity-80 flex h-14 w-full" + class="rounded-full border py-3 px-6 font-bold hover:opacity-80 flex h-14 w-full " > <div class="mx-auto my-auto flex"> - <Icon icon="send" style="my-auto h-6 mr-2" /> + <Icon icon="send" style="my-auto h-6 mr-2 text-red-300 dark:invert" /> <div class="my-auto">{$t("user.dashboard.send")}</div> </div> </button> @@ -108,7 +108,7 @@ class="rounded-full border py-3 px-6 font-bold hover:opacity-80 flex h-14 w-full" > <div class="mx-auto flex"> - <Icon icon="numpad" style="my-auto h-6 mr-2" /> + <Icon icon="numpad" style="my-auto h-6 mr-2 dark:invert" /> <div class="my-auto mt-1">{$t("user.dashboard.receive")}</div> </div> </button> diff --git a/src/routes/(app)/buy/+page.server.js b/src/routes/(app)/[username]/buy/+page.server.js index 903fec0e..903fec0e 100644 --- a/src/routes/(app)/buy/+page.server.js +++ b/src/routes/(app)/[username]/buy/+page.server.js diff --git a/src/routes/(app)/[username]/buy/+page.svelte b/src/routes/(app)/[username]/buy/+page.svelte new file mode 100644 index 00000000..48bab6ce --- /dev/null +++ b/src/routes/(app)/[username]/buy/+page.svelte @@ -0,0 +1,69 @@ +<script> + import { enhance } from "$app/forms"; + import { PUBLIC_ONRAMPER } from '$env/static/public'; + import Icon from "$comp/Icon.svelte"; + import Lock from "$comp/Lock.svelte"; + import Card from "$comp/Card.svelte"; + import Calendar from "$comp/Calendar.svelte"; + import Spinner from "$comp/Spinner.svelte"; + import { f } from "$lib/utils"; + + export let data, form, address; + + let { username, currency } = data.user; + let loading; + + let amount, n, d, cvc; +</script> + +<div class="container px-4 max-w-xl mx-auto "> + <!-- <div class="w-full flex"> + <a href="/" class="mx-auto"> + <img src="images/logo.png" alt="" class="dark:hidden block" /> + <img src="images/logo-white.png" alt="" class="hidden dark:block" /> + </a> + </div> --> + <h1 class="px-3 md:px-0 text-center text-4xl md:text-5xl font-semibold font-bebasNeue tracking-[0.2rem] mb-4"> + Buy + </h1> + + <div class="mb-6"> + <div class="flex w-full justify-center">Your bitcoin address</div> + <div class="flex w-full justify-center font-bold"> + <div> + {address} + <!-- fs5werw748272asfds584927jhjk3458927sdfs38972 --> + </div> + </div> + <!-- on:click={() => copy(address)} --> + <button class="flex mx-auto mt-5 gap-2" on:click={() => copy(address)} > + <Icon icon="copy" style="w-10 max-w-none dark:invert" /> + <div class="my-auto">Copy</div> + </button> + </div> + + <div class="flex justify-center items-center"> + <div class=""> + <iframe + style="border-radius: 10px; border: 1px solid #58585f; margin: auto;max-width: 420px;" + class="dark:hidden" + src={`https://buy.onramper.com/?apiKey=${PUBLIC_ONRAMPER}&themeName=light&containerColor=ffffff&primaryColor=7105f3ff&secondaryColor=ffffff&cardColor=f6f7f9&primaryTextColor=141519&secondaryTextColor=6b6f80&borderRadius=2&wgBorderRadius=1`} + height="630px" + width="420px" + title="Onramper widget" + allow="accelerometer; autoplay; camera; gyroscope; payment" + /> + <iframe + style="border-radius: 10px; border: 1px solid #58585f; margin: auto;max-width: 420px;" + class="hidden dark:block" + src={`https://buy.onramper.com/?apiKey=${PUBLIC_ONRAMPER}&themeName=dark&containerColor=292524ff&primaryColor=7105f3ff&secondaryColor=292524ff&cardColor=44403cff&primaryTextColor=ffffff&secondaryTextColor=ffffffff&borderRadius=2&wgBorderRadius=1`} + height="630px" + width="420px" + title="Onramper widget" + allow="accelerometer; autoplay; camera; gyroscope; payment" + /> + </div> + </div> +</div> + +<!-- src/routes/(app)/buy -->
\ No newline at end of file diff --git a/src/routes/(app)/[username]/payments/[...page]/+page.svelte b/src/routes/(app)/[username]/payments/[...page]/+page.svelte index 3237011b..b98e2cd8 100644 --- a/src/routes/(app)/[username]/payments/[...page]/+page.svelte +++ b/src/routes/(app)/[username]/payments/[...page]/+page.svelte @@ -122,20 +122,20 @@ </script> <div class="mt-24 mb-20 payments"> - <h1 class="px-3 md:px-0 text-center text-3xl md:text-4xl font-semibold mb-10"> + <h1 class="px-3 md:px-0 text-center text-4xl md:text-5xl font-semibold mb-8 font-bebasNeue tracking-[0.2rem]"> {$t("payments.header")} </h1> <div class="container w-full mx-auto text-lg px-4 max-w-xl space-y-5"> - <div class="flex text-md text-secondary relative"> - <div class="mx-auto flex justify-center w-full gap-1"> + <div class="flex text-md text-secondary dark:text-gray-200 relative"> + <div class="mx-auto flex justify-center w-full gap-3"> {#each presets as { start, end, title }, i} <a class:active={selection === i} href={`/${user.username}/payments/${getUnixTime(start) + "/"}1`} > <button - class="text-sm md:text-lg rounded-full border py-2 px-4 hover:opacity-80 min-w-[72px]" + class="text-sm md:text-lg rounded-full border dark:border-white py-2 px-4 hover:opacity-80 min-w-[72px]" > <div class="my-auto">{title}</div> </button> @@ -153,7 +153,7 @@ class:active={parseInt(p) === i + 1} > <div - class="border py-2 rounded-full border-2 w-12 h-12 hover:opacity-80 text-center" + class="py-2 rounded-full border-2 w-12 h-12 hover:opacity-80 text-center" > {i + 1} </div> @@ -170,13 +170,13 @@ <div class="font-bold" class:text-red-800={p.amount < 0}> {f(Math.abs(p.amount) * (p.rate / sats), p.currency)} {#if p.tip} - <span class="text-sm text-secondary"> + <span class="text-sm text-secondary dark:text-gray-200"> +{Math.round((p.tip / Math.abs(p.amount)) * 100)}% </span> {/if} </div> - <div class="text-secondary"> + <div class="text-secondary dark:text-gray-200"> {sat(Math.abs(p.amount) + (p.tip || 0))} </div> </div> @@ -184,7 +184,7 @@ <div class="flex my-auto"> {#if p.type === types.pot} <a href={`/pot/${p.memo}`}> - <div class="text-secondary flex"> + <div class="text-secondary dark:text-gray-200 flex"> <div class="my-auto mr-1"> <img src="/images/moneypot.png" class="w-12" alt="Pot" /> </div> @@ -197,7 +197,7 @@ <div class="my-auto"> <Avatar user={p.with} size={16} disabled={true} /> </div> - <div class="my-auto ml-1 text-secondary"> + <div class="my-auto ml-1 text-secondary dark:text-gray-200"> {p.with.username} </div> </div> @@ -207,9 +207,9 @@ class="w-24 border-4 border-transparent mr-1" alt="Bitcoin" /> - <div class="my-auto text-secondary">{p.memo}</div> + <div class="my-auto text-secondary dark:text-gray-200">{p.memo}</div> {:else} - <div class="text-secondary flex"> + <div class="text-secondary dark:text-gray-200 flex"> {#if p.type === types.lightning} <div class="text-3xl">⚡️</div> {:else if p.type === types.bitcoin} @@ -241,7 +241,7 @@ {/if} </div> - <div class="text-secondary text-right text-sm my-auto"> + <div class="text-secondary dark:text-gray-200 text-right text-sm my-auto"> <div> {format(new Date(p.created), "h:mm aaa")} </div> @@ -252,14 +252,14 @@ </div> </a> {:else} - <p class="text-secondary text-lg text-center">{$t("payments.empty")}</p> + <p class="text-secondary dark:text-gray-100 text-lg text-center">{$t("payments.empty")}</p> {/each} </div> <div class="grid grid-cols-3 w-full text-center"> - <span class="text-lg text-secondary">{$t("payments.total")}</span> - <span class="text-lg text-secondary">{$t("payments.presentValue")}</span> - <span class="text-lg text-secondary">{$t("payments.gainLoss")}</span> + <span class="text-lg text-secondary dark:text-gray-200">{$t("payments.total")}</span> + <span class="text-lg text-secondary dark:text-gray-200">{$t("payments.presentValue")}</span> + <span class="text-lg text-secondary dark:text-gray-200">{$t("payments.gainLoss")}</span> {#each Object.keys(totals) as c} {@const total = totals[c]["fiat"]} @@ -274,10 +274,10 @@ </div> <button - class="ml-auto rounded-full border py-2 px-4 w-36 hover:opacity-80 flex mx-auto" + class="ml-auto rounded-full border dark:border-white py-2 px-4 hover:opacity-80 flex mx-auto" on:click={csv} > - <Icon icon="save" style="opacity-50 mr-2 my-auto" /> + <Icon icon="save" style="opacity-50 mr-2 my-auto dark:opacity-80 dark:invert" /> <div class="my-auto">{$t("payments.export")}</div> </button> </div> @@ -285,7 +285,7 @@ <style> .active * { - @apply bg-black text-white border-black; + @apply !bg-black dark:!bg-white !text-white dark:!text-black border-black; } .payments { diff --git a/src/routes/(app)/[username]/receive/[...param]/+page.svelte b/src/routes/(app)/[username]/receive/[...param]/+page.svelte index 7a27bd67..149c762e 100644 --- a/src/routes/(app)/[username]/receive/[...param]/+page.svelte +++ b/src/routes/(app)/[username]/receive/[...param]/+page.svelte @@ -48,7 +48,7 @@ <button bind:this={submit} type="submit" - class="bg-black text-white rounded-xl w-full h-[48px] flex justify-center items-center font-semibold + class="bg-black dark:bg-swapee-purple text-white rounded-xl w-full h-[48px] flex justify-center items-center font-semibold opacity-100 hover:opacity-80" > {$t("payments.next")} diff --git a/src/routes/(app)/[username]/settings/[...tab]/+page.server.js b/src/routes/(app)/[username]/settings/[...tab]/+page.server.js index b9717b82..49b2ba0a 100644 --- a/src/routes/(app)/[username]/settings/[...tab]/+page.server.js +++ b/src/routes/(app)/[username]/settings/[...tab]/+page.server.js @@ -12,12 +12,21 @@ export const actions = { default: async ({ cookies, request }) => { let form = await fd(request); + let currentTheme = form.currentTheme; + if (form.tab === "pos") { form.notify = form.notify === "on"; form.nip5 = form.nip5 === "on"; form.prompt = form.prompt === "on"; } + if (currentTheme) { + cookies.set("colortheme", currentTheme, { + path: "/", + maxAge: 60 * 60 * 24 * 365, + }); + } + let user = { ...(await get("/me", auth(cookies))), ...form }; try { @@ -27,5 +36,5 @@ export const actions = { } return { user, success: true }; - }, + } }; diff --git a/src/routes/(app)/[username]/settings/[...tab]/+page.svelte b/src/routes/(app)/[username]/settings/[...tab]/+page.svelte index 54a2d71c..26c2830a 100644 --- a/src/routes/(app)/[username]/settings/[...tab]/+page.svelte +++ b/src/routes/(app)/[username]/settings/[...tab]/+page.svelte @@ -30,6 +30,7 @@ let { user, token, rates, tab, cookies } = data; let prev; + let currentTheme = ""; $: update(data); let update = () => { @@ -189,21 +190,22 @@ > <input type="hidden" name="pin" value={$pin} /> <input type="hidden" name="tab" value={tab} /> + <input type="hidden" name="currentTheme" value={currentTheme} /> <div class="mt-24 mb-20 px-3 md:px-0 w-full md:w-[400px] mx-auto space-y-8"> <div class="header"> - <h1 class="text-center text-3xl md:text-4xl font-semibold mb-10"> + <h1 class="text-center text-4xl md:text-5xl font-semibold mb-8 font-bebasNeue tracking-[0.2rem]"> {$t("user.settings.header")} </h1> <div - class="font-bold flex justify-around items-center border-b pb-3 text-secondary" + class="font-bold flex justify-around items-center border-b dark:border-b-gray-50 pb-3 text-secondary" > {#each tabs.filter((t) => t.name !== "shopify") as { name, key }} <a href={`/${user.username}/settings/${name}`}> <button type="button" - class="hover:opacity-80" + class="hover:opacity-80 dark:text-gray-100" class:text-black={tab === name || (tab === "shopify" && name === "pos")} >{$t(`user.settings.${key}`)}</button @@ -213,16 +215,16 @@ </div> </div> - <svelte:component this={comp} {user} {rates} {submit} /> + <svelte:component this={comp} {user} {rates} {submit} on:changeTheme={(e) => currentTheme = e.detail }/> </div> <div - class="z-10 fixed bottom-0 bg-white shadow border-t w-full flex justify-center items-center py-3" + class="z-10 fixed bottom-0 bg-white dark:bg-black shadow border-t dark:border-t-gray-50 w-full flex justify-center items-center py-3" > <button bind:this={submit} type="submit" - class="border-2 border-black rounded-xl font-semibold mx-auto py-3 w-40 hover:opacity-80" + class="border-2 border-black dark:bg-white dark:text-black rounded-xl font-semibold mx-auto py-3 w-40 hover:opacity-80" class:bg-black={submitting} > {#if submitting} diff --git a/src/routes/(app)/[username]/settings/[...tab]/_account.svelte b/src/routes/(app)/[username]/settings/[...tab]/_account.svelte index 15ee7b0c..a4bb2b68 100644 --- a/src/routes/(app)/[username]/settings/[...tab]/_account.svelte +++ b/src/routes/(app)/[username]/settings/[...tab]/_account.svelte @@ -73,7 +73,7 @@ </script> <div> - <label for="username" class="font-bold mb-1 block" + <label for="username" class="font-bold mb-3 block" >{$t("user.settings.username")}</label > <div class="flex mb-2"> @@ -81,26 +81,26 @@ type="text" name="username" bind:value={user.username} - class="w-auto min-w-0 pr-1 grow" + class="w-auto min-w-0 pr-1 grow dark:bg-stone-800 dark:border-0" /> </div> </div> <div> - <label for="display" class="font-bold mb-1 block" + <label for="display" class="font-bold mb-3 block" >{$t("user.settings.displayName")}</label > - <input type="text" name="display" bind:value={user.display} /> + <input type="text" name="display" bind:value={user.display} class="dark:bg-stone-800 dark:border-0" /> </div> <div class="space-y-1 relative"> <label for="email" class="font-bold block">{$t("user.settings.email")}</label> - <p class="text-secondary"> + <p class="text-secondary dark:text-gray-200"> {$t("user.settings.emailDescription")} </p> <div class="relative"> - <input type="text" name="email" bind:value={user.email} /> + <input type="text" name="email" bind:value={user.email} class="dark:bg-stone-800 dark:border-0" /> {#if user.verified} <Icon icon="check" style="absolute right-5 top-3 w-8" /> {:else if user.email} @@ -114,6 +114,7 @@ <div class="flex"> {#if $avatar || user.profile} + <!-- svelte-ignore a11y-no-static-element-interactions --> <div class="relative rounded-full overflow-hidden text-center w-20 h-20 my-auto hover:opacity-80 cursor-pointer" on:click={selectAvatar} @@ -121,11 +122,12 @@ > <img src={$avatar?.src || `/api/public/${user.profile}.webp`} - class="absolute w-full h-full object-cover object-center visible overflow-hidden" + class="absolute w-full h-full object-cover object-center visible overflow-hidden " alt={user.username} /> </div> {:else} + <!-- svelte-ignore a11y-no-static-element-interactions --> <div class="rounded-full border-4 border-white p-4 bg-gradient-to-r {$colorTheme} w-24 my-auto hover:opacity-80 cursor-pointer" on:click={selectAvatar} @@ -138,7 +140,7 @@ <!-- found missing translation --> <button type="button" - class="border rounded-2xl font-bold w-24 text-center px-0 py-2 hover:opacity-80" + class="border rounded-2xl font-bold w-24 text-center px-0 py-2 hover:opacity-80 dark:border-white" on:click={selectAvatar} on:keydown={selectAvatar}>{$t("user.settings.select")}</button > @@ -157,11 +159,12 @@ </div> <div> - <div class="flex justify-between items-center"> + <div class="flex justify-between items-center mb-3"> <span class="font-bold">{$t("user.settings.bannerImage")}</span> </div> {#if $banner || user.banner} + <!-- svelte-ignore a11y-no-noninteractive-element-interactions --> <img src={$banner ? $banner.src : `/api/public/${user.banner}.webp`} class="w-full object-cover object-center visible overflow-hidden h-48 mb-4 hover:opacity-80" @@ -170,8 +173,9 @@ alt="Banner" /> {:else} + <!-- svelte-ignore a11y-no-static-element-interactions --> <div - class="bg-gradient-to-r {$colorTheme} w-full h-48 mb-4 cursor-pointer hover:opacity-80" + class="bg-gradient-to-r {$colorTheme} dark:!from-stone-800 dark:!to-stone-800 w-full h-48 mb-4 cursor-pointer hover:opacity-80" on:click={selectBanner} on:keydown={selectBanner} alt="Banner" @@ -180,7 +184,7 @@ <button type="button" - class="border rounded-2xl font-bold w-24 text-center px-0 py-2 hover:opacity-80" + class="border dark:border-white rounded-2xl font-bold w-24 text-center px-0 py-2 hover:opacity-80 " on:click={selectBanner} on:keydown={selectBanner}>{$t("user.settings.select")}</button > @@ -197,7 +201,7 @@ </div> <div> - <label for="address" class="font-bold mb-1 block" + <label for="address" class="font-bold mb-3 block" >{$t("user.settings.about")}</label > <textarea @@ -205,5 +209,6 @@ name="address" bind:value={user.address} placeholder={$t("user.settings.aboutPlaceholder")} + class="dark:bg-stone-800 dark:border-0 dark:placeholder:text-gray-300" /> </div> diff --git a/src/routes/(app)/[username]/settings/[...tab]/_pos.svelte b/src/routes/(app)/[username]/settings/[...tab]/_pos.svelte index 539cfd5e..68b5e05f 100644 --- a/src/routes/(app)/[username]/settings/[...tab]/_pos.svelte +++ b/src/routes/(app)/[username]/settings/[...tab]/_pos.svelte @@ -1,30 +1,59 @@ <script> + import { enhance } from '$app/forms'; import Icon from "$comp/Icon.svelte"; import LocaleSelector from "$comp/LocaleSelector.svelte"; import Toggle from "$comp/Toggle.svelte"; import { t } from "$lib/translations"; import { success, fail } from "$lib/utils"; import { page } from "$app/stores"; + import { onMount } from 'svelte'; + import ThemeToggle from '../../../../../components/buttons/ThemeToggle.svelte'; + import { createEventDispatcher } from 'svelte' + const dispatch = createEventDispatcher() export let user, rates, submit; let fiats = Object.keys(rates); + + let themeSelected; + let toggleThemeForm; + + onMount(() => { + themeSelected = document.documentElement.classList[0]; + }) + + function toggleThemeSelected() { + themeSelected = themeSelected == "dark" ? "light" : "dark"; + submitUpdateTheme(themeSelected); + } + + function submitUpdateTheme(theme) { + const htmlClasses = document.documentElement.classList; + if (theme == "dark" && !(htmlClasses.contains("dark"))) { + htmlClasses.add("dark"); + htmlClasses.remove("light"); + } else if (theme == "light" && !(htmlClasses.contains("light"))) { + htmlClasses.add("light"); + htmlClasses.remove("dark"); + } + dispatch("changeTheme", theme) + } </script> <div> - <label for="language" class="font-bold block mb-1" + <label for="language" class="font-bold block mb-3" >{$t("user.settings.locale")}</label > - <LocaleSelector style="select-styles block py-3 w-full" /> + <LocaleSelector style="select-styles block py-3 w-full dark:bg-stone-800 dark:border-0" /> </div> <div> - <label for="currency" class="font-bold block mb-1" + <label for="currency" class="font-bold block mb-3 " >{$t("user.settings.localCurrency")}</label > <select name="currency" - class="select-styles block py-3 w-full" + class="select-styles block py-3 w-full dark:bg-stone-800 dark:border-0" value={user.currency} > {#each fiats as fiat} @@ -35,10 +64,23 @@ <div> <div class="flex justify-between items-center"> + <span class="font-bold">Dark Theme</span> + {#if themeSelected} + <button type="button" on:click={toggleThemeSelected} class="focus:ring-4 ring-gray-300 dark:ring-gray-800 rounded-full inline-flex relative items-center mr-5 cursor-pointer "> + <div + class="w-11 h-6 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-0.5 {themeSelected == 'dark' ? ' dark:bg-green-500' : 'bg-gray-200 after:-translate-x-full'} after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 " + /> + </button> + {/if} + </div> +</div> + +<div> + <div class="flex justify-between items-center"> <span class="font-bold">{$t("user.settings.notifications")}</span> <Toggle id="notify" bind:value={user.notify} /> </div> - <p class="text-secondary mt-1 w-9/12"> + <p class="text-secondary dark:text-gray-200 mt-1 w-9/12"> {$t("user.settings.notificationsDesc")} </p> </div> @@ -48,7 +90,7 @@ <span class="font-bold">{$t("user.settings.tipPrompt")}</span> <Toggle id="prompt" bind:value={user.prompt} /> </div> - <p class="text-secondary mt-1 w-9/12"> + <p class="text-secondary dark:text-gray-200 mt-1 w-9/12"> {$t("user.settings.tipPromptDescription")} </p> </div> @@ -58,7 +100,7 @@ <span class="font-bold">{$t("user.settings.publishNip5")}</span> <Toggle id="nip5" bind:value={user.nip5} /> </div> - <p class="text-secondary mt-1 w-9/12"> + <p class="text-secondary dark:text-gray-200 mt-1 w-9/12"> {$t("user.settings.nip5a")} <span class="font-bold">{user.username}@{$page.url.host}</span> {$t("user.settings.nip5b")} @@ -70,7 +112,7 @@ type="button" class="flex rounded-full border py-2 px-4 font-bold hover:opacity-80 w-full gap-2 my-5 justify-center" > - <img src="/icons/shopify.svg" class="w-8" /> + <img src="/icons/shopify.svg" alt="" class="w-8" /> <div class="my-auto">Shopify Integration</div> </button> </a> diff --git a/src/routes/(app)/[username]/settings/[...tab]/_security.svelte b/src/routes/(app)/[username]/settings/[...tab]/_security.svelte index 38bf726c..52565af8 100644 --- a/src/routes/(app)/[username]/settings/[...tab]/_security.svelte +++ b/src/routes/(app)/[username]/settings/[...tab]/_security.svelte @@ -155,19 +155,19 @@ <input type="hidden" name="confirm" bind:value={password} /> <div class="relative mb-5"> - <label for="password" class="block font-bold block mb-1" + <label for="password" class="block font-bold mb-3 " >{$t("user.settings.newPassword")}</label > {#if revealPassword} - <input name="password" type="text" bind:value={password} /> + <input name="password" type="text" bind:value={password} class="dark:bg-stone-800 dark:border-0" /> {:else} - <input name="password" type="password" bind:value={password} /> + <input name="password" type="password" bind:value={password} class="dark:bg-stone-800 dark:border-0" /> {/if} <button type="button" on:click={togglePassword} on:keydown={togglePassword} - class="absolute right-5 top-11" + class="absolute right-5 dark:invert-[95%] {revealPassword ? 'top-[54px]' : 'top-[52px]'} " > <Icon icon={revealPassword ? "eye" : "eye-off"} /> </button> @@ -179,7 +179,7 @@ ? $t("user.settings.verifyPIN") : $t("user.settings.securityPIN")}</span > - <p class="text-secondary mb-1"> + <p class="text-secondary dark:text-gray-200 mb-4"> {$t("user.settings.securityPINDescription")} </p> {#if verifying} @@ -192,8 +192,8 @@ notify={false} /> {:else} - <button type="button" class="primary" on:click={togglePin} - ><Icon icon="lock" style="mr-1" /> + <button type="button" class="py-2 px-4 font-bold rounded-full mx-auto border-[1px] flex border-gray-200 dark:border-gray-50" on:click={togglePin} + ><Icon icon="lock" style="mr-1 dark:invert" /> {user.haspin ? $t("user.settings.disablePIN") : $t("user.settings.enablePIN")}</button @@ -206,7 +206,7 @@ <label for="locktime" class="font-bold mb-1" >{$t("user.settings.autoLock")}</label > - <p class="text-secondary mb-1"> + <p class="text-secondary dark:text-gray-200 mb-1"> {$t("user.settings.autoLockDescription")} </p> <select @@ -224,8 +224,8 @@ {/if} <div> - <span class="font-bold mb-1">{$t("user.settings.twofa")}</span> - <p class="text-secondary mb-4"> + <span class="font-bold mb-4">{$t("user.settings.twofa")}</span> + <p class="text-secondary dark:text-gray-200 mb-4"> {$t("user.settings.twofaDescription")} </p> @@ -239,18 +239,18 @@ <b>{otp.secret}</b> </div> - <button type="button" class="primary" on:click={startConfirming2fa}> - <Icon icon="mobile" style="mr-1" /> + <button type="button" class="py-2 px-4 font-bold rounded-full mx-auto border-[1px] flex border-gray-200 dark:border-gray-50" on:click={startConfirming2fa}> + <Icon icon="mobile" style="mr-1 dark:invert" /> Confirm </button> {:else if user.twofa} - <button type="button" class="primary" on:click={startDisabling2fa}> - <Icon icon="mobile" style="mr-1" /> + <button type="button" class="py-2 px-4 font-bold rounded-full mx-auto border-[1px] flex border-gray-200 dark:border-gray-50" on:click={startDisabling2fa}> + <Icon icon="mobile" style="mr-1 dark:invert" /> {$t("user.settings.twofaDisable")} </button> {:else} - <button type="button" class="primary" on:click={startEnabling2fa}> - <Icon icon="mobile" style="mr-1" /> + <button type="button" class="py-2 px-4 font-bold rounded-full mx-auto border-[1px] flex border-gray-200 dark:border-gray-50" on:click={startEnabling2fa}> + <Icon icon="mobile" style="mr-1 dark:invert" /> {$t("user.settings.twofaSetup")} </button> {/if} @@ -271,22 +271,22 @@ >{$t("user.settings.seedPhrase")}</label > - <p class="text-secondary mb-1"> + <p class="text-secondary dark:text-gray-200 mb-4"> {$t("user.settings.seedDescription")} </p> - <button type="button" class="primary" on:click={toggleSeed}> - <Icon icon="warning" style="mr-1 w-6 my-auto" /> + <button type="button" class="py-2 px-4 font-bold rounded-full mx-auto border-[1px] flex border-gray-200 dark:border-gray-50" on:click={toggleSeed}> + <Icon icon="warning" style="mr-2 w-6 my-auto dark:invert" /> {revealSeed ? $t("user.settings.hideSeed") : $t("user.settings.revealSeed")} </button> {#if revealSeed} - <div class="text-lg"> + <div class="text-lg my-6"> {mnemonic} </div> - <button type="button" class="primary" on:click={() => copy(mnemonic)}> - <Icon icon="copy" style="mr-1 w-6 my-auto" /> + <button type="button" class="py-2 px-4 font-bold rounded-full mx-auto border-[1px] flex border-gray-200 dark:border-gray-50" on:click={() => copy(mnemonic)}> + <Icon icon="copy" style="mr-1 w-6 my-auto dark:invert" /> Copy </button> {/if} @@ -297,22 +297,22 @@ >{$t("user.settings.nostrKeys")}</label > - <p class="text-secondary mb-1"> + <p class="text-secondary dark:text-gray-200 mb-4"> {$t("user.settings.nostrDescription")} </p> - <button type="button" class="primary" on:click={toggleNsec}> - <Icon icon="warning" style="mr-1 w-6 my-auto" /> + <button type="button" class="py-2 px-4 font-bold rounded-full mx-auto border-[1px] flex border-gray-200 dark:border-gray-50" on:click={toggleNsec}> + <Icon icon="warning" style="mr-2 w-6 my-auto dark:invert" /> {revealNsec ? $t("user.settings.hideNsec") : $t("user.settings.revealNsec")} </button> {#if revealNsec} - <div class="text-lg break-all"> + <div class="text-lg break-all my-6"> {nsec} </div> - <button type="button" class="primary" on:click={() => copy(nsec)}> - <Icon icon="copy" style="mr-1 w-6 my-auto" /> + <button type="button" class="py-2 px-4 font-bold rounded-full mx-auto border-[1px] flex border-gray-200 dark:border-gray-50" on:click={() => copy(nsec)}> + <Icon icon="copy" style="mr-1 w-6 my-auto dark:invert" /> Copy </button> {/if} diff --git a/src/routes/(app)/buy/+page.svelte b/src/routes/(app)/buy/+page.svelte deleted file mode 100644 index caed8f83..00000000 --- a/src/routes/(app)/buy/+page.svelte +++ /dev/null @@ -1,52 +0,0 @@ -<script> - import { enhance } from "$app/forms"; - import { PUBLIC_ONRAMPER } from '$env/static/public'; - import Icon from "$comp/Icon.svelte"; - import Lock from "$comp/Lock.svelte"; - import Card from "$comp/Card.svelte"; - import Calendar from "$comp/Calendar.svelte"; - import Spinner from "$comp/Spinner.svelte"; - import { copy, f } from "$lib/utils"; - - export let data; - - let { address } = data; - let { username, currency } = data.user; - let loading; - - let amount, n, d, cvc; -</script> - -<div class="container px-4 max-w-xl mx-auto mt-10 space-y-5"> - <div class="w-full flex"> - <a href="/" class="mx-auto"> - <Icon icon="logo" /> - </a> - </div> - - <div class="pt-10"> - <div class="flex w-full justify-center">Your bitcoin address</div> - <div class="flex w-full justify-center font-bold"> - <div> - {address} - </div> - </div> - <button class="flex mx-auto mt-5" on:click={() => copy(address)} - ><Icon icon="copy" style="w-10 max-w-none" /> - <div class="my-auto">Copy</div></button - > - </div> - - <div class="flex justify-center items-center"> - <div class="shadow-xl rounded-3xl px-10 pt-5 pb-10 space-y-5 w-full mx-5"> - <iframe - style="border-radius: 4px; border: 1px solid #58585f; margin: auto;max-width: 420px" - src={`https://buy.onramper.com/?apiKey=${PUBLIC_ONRAMPER}`} - height="630px" - width="420px" - title="Onramper widget" - allow="accelerometer; autoplay; camera; gyroscope; payment" - /> - </div> - </div> -</div> diff --git a/src/routes/(app)/forgot/+page.svelte b/src/routes/(app)/forgot/+page.svelte index 378262cc..127241ce 100644 --- a/src/routes/(app)/forgot/+page.svelte +++ b/src/routes/(app)/forgot/+page.svelte @@ -14,15 +14,16 @@ <div class="pt-10"> <div class="w-[243px] mx-auto mb-10"> <a href="/"> - <Icon icon="logo" /> + <img src="images/logo.png" alt="" class="dark:hidden block" /> + <img src="images/logo-white.png" alt="" class="hidden dark:block" /> </a> </div> <div class="flex justify-center items-center"> <div - class="shadow-xl rounded-3xl p-10 pb-12 space-y-5 w-full mx-5 md:mx-0 md:w-[400px]" + class="shadow-xl dark:bg-stone-800 rounded-3xl p-10 pb-12 space-y-5 w-full mx-5 md:mx-0 md:w-[400px]" > - <h1 class="text-2xl font-bold text-center">{$t("login.reset")}</h1> + <h1 class="text-4xl font-bebasNeue tracking-[0.25rem] font-bold text-center dark:text-gray-50">{$t("login.reset")}</h1> {#if form?.error} <div class="text-red-600 text-center" in:fly> @@ -31,7 +32,7 @@ {/if} {#if form?.success} - <div class="text-secondary"> + <div class="text-secondary dark:text-gray-200"> A password reset link will be sent to your email if we have it on file. </div> @@ -39,7 +40,7 @@ <div class="flex w-full"> <a href="/login" - class="bg-black text-white w-full rounded-2xl p-4 font-semibold hover:opacity-80 text-center" + class="bg-black text-white w-full rounded-2xl p-4 font-semibold hover:opacity-80 text-center dark:bg-swapee-purple active:scale-95 transition-all" > Continue </a> @@ -52,7 +53,7 @@ name="email" type="text" required - class="bg-primary" + class="input-swapee mt-1" bind:value={email} use:focus autocapitalize="none" @@ -61,7 +62,7 @@ <button type="submit" - class="bg-black text-white w-full rounded-2xl p-4 font-semibold hover:opacity-80" + class="bg-black dark:bg-swapee-purple active:scale-95 transition-all text-white w-full rounded-2xl p-4 font-semibold hover:opacity-80" disabled={loading} > {#if loading} diff --git a/src/routes/(app)/login/+page.svelte b/src/routes/(app)/login/+page.svelte index cebbf41c..e10bc206 100644 --- a/src/routes/(app)/login/+page.svelte +++ b/src/routes/(app)/login/+page.svelte @@ -67,8 +67,11 @@ applyAction(result); loading = false; } + + </script> + {#if need2fa} <Pin bind:value={token} title="Enter 2FA Code" {cancel} notify={false} /> {/if} @@ -76,15 +79,16 @@ <div class="pt-10"> <div class="w-[243px] mx-auto mb-10"> <a href="/"> - <Icon icon="logo" /> + <img src="images/logo.png" alt="" class="dark:hidden block" /> + <img src="images/logo-white.png" alt="" class="hidden dark:block" /> </a> </div> <div class="flex justify-center items-center"> <div - class="shadow-xl rounded-3xl p-10 pb-12 space-y-5 w-full mx-5 md:mx-0 md:w-[400px]" + class="shadow-xl dark:bg-stone-800 rounded-3xl p-5 sm:p-10 pb-8 sm:pb-12 space-y-5 w-full mx-5 md:mx-0 md:w-[400px] " > - <h1 class="text-2xl font-bold text-center">{$t("login.signIn")}</h1> + <h1 class="text-4xl text-center dark:text-gray-50 font-bold font-bebasNeue tracking-[0.25rem]">{$t("login.signIn")}</h1> {#if form?.error} <div class="text-red-600 text-center" in:fly> @@ -112,7 +116,7 @@ name="username" type="text" required - class="bg-primary" + class="input-swapee mt-1" bind:value={username} use:focus autocapitalize="none" @@ -128,7 +132,7 @@ name="password" type="text" required - class="bg-primary" + class="input-swapee mt-1" bind:value={$password} autocapitalize="none" /> @@ -137,7 +141,7 @@ name="password" type="password" required - class="bg-primary" + class="input-swapee mt-1" bind:value={$password} autocapitalize="none" /> @@ -145,21 +149,21 @@ <button type="button" on:click={() => (revealPassword = !revealPassword)} - class="absolute right-5 top-10" + class="absolute right-5 {revealPassword ? 'top-[46px]' : 'top-11'} dark:invert" > <Icon icon={revealPassword ? "eye" : "eye-off"} /> </button> </div> <div class="flex justify-end items-center"> - <a href="/forgot" class="underline underline-offset-4 text-black" + <a href="/forgot" class="underline underline-offset-4 text-black dark:text-white decoration-swapee-purple hover:opacity-75 decoration-2 " >{$t("login.forgotUserOrPassword")}</a > </div> <button type="submit" - class="bg-black text-white w-full rounded-2xl p-4 font-semibold hover:opacity-80" + class="bg-black text-white w-full rounded-2xl p-4 font-semibold hover:opacity-80 dark:bg-swapee-purple active:scale-95 transition-all " disabled={loading} bind:this={btn} > @@ -171,11 +175,11 @@ </button> </form> - <p class="text-secondary text-center font-medium"> + <p class="text-secondary dark:text-gray-200 text-center font-medium"> {$t("login.haveAccount")} <a href={"/register"} - class="block md:inline text-black underline underline-offset-4 hover:opacity-80" + class="block md:inline-block underline underline-offset-4 text-black dark:text-white decoration-swapee-purple hover:opacity-75 decoration-2" > {$t("login.register")} </a> diff --git a/src/routes/(app)/payment/[id]/+page.svelte b/src/routes/(app)/payment/[id]/+page.svelte index dbaea042..7c8c78e0 100644 --- a/src/routes/(app)/payment/[id]/+page.svelte +++ b/src/routes/(app)/payment/[id]/+page.svelte @@ -70,8 +70,8 @@ </a> <div class="container mx-auto max-w-lg px-4 space-y-8 break-all text-2xl"> - <h1 class="px-3 md:px-0 text-center text-3xl md:text-4xl font-semibold mb-10"> - {$t(amount < 0 ? "payments.sent" : "payments.received")} + <h1 class="px-3 md:px-0 text-center text-4xl md:text-5xl font-semibold mb-8 font-bebasNeue tracking-[0.2rem]"> + {$t(amount < 0 ? "payments.sent" : "payments.received")} </h1> {#if p.with} diff --git a/src/routes/(app)/register/+page.svelte b/src/routes/(app)/register/+page.svelte index 5783059a..82bfbde4 100644 --- a/src/routes/(app)/register/+page.svelte +++ b/src/routes/(app)/register/+page.svelte @@ -155,15 +155,16 @@ {/if} <div class="pt-4"> - <div class="w-[243px] mx-auto"> + <div class="w-[243px] mx-auto mb-10 mt-6"> <a href="/"> - <Icon icon="logo" /> + <img src="images/logo.png" alt="" class="dark:hidden block" /> + <img src="images/logo-white.png" alt="" class="hidden dark:block mb-5" /> </a> </div> <div class="flex justify-center items-center"> <div - class="shadow-xl rounded-3xl p-4 pt-0 space-y-5 w-full mx-5 md:mx-0 md:w-[400px]" + class="shadow-xl dark:bg-stone-800 rounded-3xl p-5 sm:p-10 pb-8 sm:pb-12 pt-3 sm:pt-6 space-y-5 w-full mx-5 md:mx-0 md:w-[400px]" > <input type="file" @@ -174,11 +175,13 @@ <div class="relative"> <button - class="absolute w-8 h-12 left-12 bg-white rounded top-12" + class="absolute w-8 h-12 left-[5%] min-[400px]:left-12 bg-white dark:bg-stone-700 rounded top-12" on:click={decr} > - <Icon icon="chevron-left" style="w-8 " /> + <Icon icon="chevron-left" style="w-8 dark:invert" /> </button> + <!-- svelte-ignore a11y-click-events-have-key-events --> + <!-- svelte-ignore a11y-no-static-element-interactions --> <div class="relative w-32 mx-auto" on:click={selectAvatar}> <button class="w-32 h-32 rounded-full border-4 border-white overflow-hidden flex mx-auto relative" @@ -190,16 +193,16 @@ /> </button> <button - class="absolute bg-white rounded-full p-2 mx-auto right-0 bottom-0 z-10 bg-opacity-80" + class="absolute bg-white dark:bg-stone-700 rounded-full p-2 mx-auto right-0 bottom-0 z-10 bg-opacity-80" > - <Icon icon="upload" style="w-8" /> + <Icon icon="upload" style="w-8 dark:invert" /> </button> </div> <button - class="absolute w-8 h-12 right-12 bg-white rounded top-12" + class="absolute w-8 h-12 right-[5%] min-[400px]:right-12 bg-white dark:bg-stone-700 rounded top-12" on:click={incr} > - <Icon icon="chevron-left" style="w-8 rotate-180" /> + <Icon icon="chevron-left" style="w-8 rotate-180 dark:invert" /> </button> </div> @@ -231,7 +234,7 @@ name="username" type="text" required - class="bg-primary" + class="input-swapee mt-1" bind:value={username} on:focus={clear} autocapitalize="none" @@ -239,10 +242,10 @@ <button type="button" on:click={refresh} - class="absolute right-0 top-4" + class="absolute right-0 top-5" tabindex="5" > - <Icon icon="random" style="w-10 m-4" /> + <Icon icon="random" style="w-10 m-4 dark:invert" /> </button> </div> @@ -256,7 +259,7 @@ name="password" type="text" required - class="bg-primary" + class="input-swapee mt-1" bind:value={$password} autocapitalize="none" /> @@ -266,7 +269,7 @@ name="password" type="password" required - class="bg-primary" + class="input-swapee mt-1" bind:value={$password} autocapitalize="none" on:focus={clear} @@ -276,20 +279,20 @@ type="button" tabindex="4" on:click={() => (revealPassword = !revealPassword)} - class="absolute right-0 top-4" + class="absolute right-0 {revealPassword ? 'top-[22px]' : 'top-5'}" > - <Icon icon={revealPassword ? "eye" : "eye-off"} style="m-6" /> + <Icon icon={revealPassword ? "eye" : "eye-off"} style="m-6 dark:invert" /> </button> </div> - <p class="text-secondary text-sm"> + <p class="text-secondary dark:text-gray-200 text-sm"> {$t("login.passwordRecommendation")} </p> <button tabindex="3" - type="submit" - class="bg-black text-white w-full rounded-2xl p-4 font-semibold hover:opacity-80" + type="button" + class="bg-black dark:bg-swapee-purple text-white w-full rounded-2xl p-4 font-semibold hover:opacity-80 active:scale-95 transition-all" disabled={loading} bind:this={btn} > @@ -301,11 +304,11 @@ </button> </form> - <p class="text-secondary text-center font-medium"> + <p class="text-secondary dark:text-gray-200 text-center font-medium"> {$t("login.haveAccount")} <a href={"/login"} - class="block md:inline text-black underline underline-offset-4 hover:opacity-80" + class="block md:inline underline underline-offset-4 text-black dark:text-white decoration-swapee-purple hover:opacity-75 decoration-2" > {$t("login.signIn")} </a> diff --git a/src/routes/(app)/send/+layout.svelte b/src/routes/(app)/send/+layout.svelte index 5e379c32..0f412759 100644 --- a/src/routes/(app)/send/+layout.svelte +++ b/src/routes/(app)/send/+layout.svelte @@ -13,4 +13,4 @@ <Pin bind:value={$pin} {cancel} /> {/if} -<slot /> +<slot />
\ No newline at end of file diff --git a/src/routes/(app)/send/[...text]/+page.svelte b/src/routes/(app)/send/[...text]/+page.svelte index 343bffd5..96df35ad 100644 --- a/src/routes/(app)/send/[...text]/+page.svelte +++ b/src/routes/(app)/send/[...text]/+page.svelte @@ -32,8 +32,8 @@ <svelte:window bind:innerWidth={w} /> <AppHeader {data} /> -<div class="container px-4 max-w-lg mx-auto space-y-5 mt-20"> - <h1 class="px-3 md:px-0 text-center text-3xl md:text-4xl font-semibold"> +<div class="container px-4 max-w-xl mx-auto space-y-7 mt-24"> + <h1 class="px-3 md:px-0 text-center text-4xl md:text-5xl font-semibold font-bebasNeue tracking-[0.2rem]"> {$t("payments.send")} </h1> @@ -46,28 +46,28 @@ </div> {/if} - <div class="mb-2"> + <div class="mb-4"> <input type="hidden" name="text" bind:value={text} /> <textarea {placeholder} on:keypress={keypress} - class="w-full p-4 border rounded-xl h-48" + class="w-full p-4 border border-stone-400 focus:outline-none focus:ring-2 hover:ring-2 ring-stone-900 dark:ring-white transition-all duration-500 rounded-xl h-48 dark:bg-stone-800 placeholder:text-stone-300" bind:value={text} bind:this={textarea} /> </div> - <div class="grid grid-cols-2 md:grid-cols-4 gap-2"> + <div class="grid grid-cols-2 md:grid-cols-4 gap-3"> <a href={`/qr/${encodeURIComponent(text)}`} class:invisible={!text?.length} > <button type="button" - class="flex border rounded-full px-6 py-2 font-bold hover:opacity-80 mr-1 w-full" + class="flex border dark:border-white rounded-full px-6 py-2 font-bold hover:opacity-80 mr-1 w-full" > - <Icon icon="qr" style="mr-2 w-6 my-auto invert" /> + <Icon icon="qr" style="mr-2 w-6 my-auto invert dark:invert-0" /> <div class="my-auto">{$t("user.send.makeQR")}</div> </button> </a> @@ -75,19 +75,19 @@ <a href="/scan" class="w-full"> <button type="button" - class="flex border rounded-full px-6 py-2 font-bold hover:opacity-80 mr-1 w-full" + class="flex border dark:border-white rounded-full px-6 py-2 font-bold hover:opacity-80 mr-1 w-full" > - <Icon icon="camera" style="mr-2 w-6 my-auto" /> + <Icon icon="camera" style="mr-2 w-6 my-auto dark:invert" /> <div class="my-auto">{$t("user.send.scan")}</div> </button> </a> <button type="button" - class="flex border rounded-full px-6 py-2 font-bold hover:opacity-80 mr-1" + class="flex border dark:border-white rounded-full px-6 py-2 font-bold hover:opacity-80 " on:click={paste} > - <Icon icon="paste" style="mr-2 w-6 my-auto" /> + <Icon icon="paste" style="mr-2 w-6 my-auto dark:invert" /> <div class="my-auto">{$t("user.send.paste")}</div> </button> @@ -96,7 +96,7 @@ type="submit" class="{!text ? 'opacity-50' - : 'opacity-100 hover:opacity-80'} bg-black text-white border rounded-full px-6 py-2 font-bold" + : 'opacity-100 hover:opacity-80'} bg-black dark:bg-swapee-purple text-white border rounded-full px-6 py-2 font-bold" > {$t("user.send.next")} </button> diff --git a/src/routes/(app)/support/+page.svelte b/src/routes/(app)/support/+page.svelte index 4dc2e4d1..87cdc259 100644 --- a/src/routes/(app)/support/+page.svelte +++ b/src/routes/(app)/support/+page.svelte @@ -57,7 +57,7 @@ <AppHeader {data} /> {/if} -<div class="container px-4 max-w-lg mx-auto mt-20 space-y-8"> +<div class="container px-4 max-w-lg mx-auto mt-24 space-y-8"> {#if sent} <h1 class="text-center text-3xl md:text-4xl font-semibold">Thank you!</h1> <div class="text-center text-lg text-secondary"> @@ -73,11 +73,11 @@ </a> </div> {:else} - <h1 class="text-center text-3xl md:text-4xl font-semibold mb-8"> + <h1 class="text-center text-4xl md:text-5xl font-semibold mb-8 font-bebasNeue tracking-[0.2rem]"> {$t("user.support.header")} </h1> - <p class="text-secondary text-lg"> + <p class="text-secondary dark:text-gray-200 text-lg"> Fill out this form or email us directly at <a class="underline" href="mailto:[email protected]">[email protected]</a @@ -85,12 +85,12 @@ </p> <form on:submit={submit}> - <div class="mb-4"> + <div class="mb-6"> <label for="account" class="font-semibold" >{$t("user.support.accountName")}</label > <input - class="bg-primary" + class="input-swapee mt-3" type="text" name="account" required @@ -98,12 +98,12 @@ /> </div> - <div class="mb-4"> + <div class="mb-6"> <label for="email" class="font-semibold" >{$t("user.support.email")}</label > <input - class="bg-primary" + class="input-swapee mt-3" type="email" name="email" bind:value={email} @@ -111,13 +111,13 @@ /> </div> - <div class="mb-4"> + <div class="mb-6"> <label for="message" class="font-semibold" >{$t("user.support.message")}</label > <textarea rows={5} - class="bg-primary" + class="input-swapee mt-3" type="text" name="message" bind:value={message} @@ -130,7 +130,7 @@ disabled={!email || !message} class="g-recaptcha {!email || !message ? 'opacity-50' - : 'opacity-100'} bg-black text-white font-bold rounded-xl py-3 w-full mx-auto {email && + : 'opacity-100'} bg-black dark:bg-swapee-purple text-white font-bold rounded-xl py-3 w-full mx-auto {email && message ? 'hover:opacity-80' : ''}">{$t("user.support.send")}</button diff --git a/src/routes/(static)/+layout.svelte b/src/routes/(static)/+layout.svelte index 13073d5a..cfee0dd1 100644 --- a/src/routes/(static)/+layout.svelte +++ b/src/routes/(static)/+layout.svelte @@ -9,7 +9,11 @@ <SvelteToast options={{ reversed: true, intro: { y: 192 } }} /> <LandingHeader {user} /> -<main class="container flex px-10 md:px-40 mx-auto min-h-[600px] pb-20"> +<main class="container flex px-10 lg:px-40 mx-auto min-h-[600px] pb-20"> <slot /> </main> <Footer /> + +<style> + +</style>
\ No newline at end of file diff --git a/src/routes/(static)/docs/+page.svelte b/src/routes/(static)/docs/+page.svelte index 451b57f3..0f5e20cf 100644 --- a/src/routes/(static)/docs/+page.svelte +++ b/src/routes/(static)/docs/+page.svelte @@ -15,23 +15,23 @@ </script> <div class="space-y-8 lg:text-xl mt-20 pt-20 md:pt-0 w-full max-w-full"> - <h1 class="text-4xl">Documentation</h1> + <h1 class="text-5xl f_bebas_neue tracking-[0.2rem] font-bold">Documentation</h1> - <p class="text-secondary"> + <p class="text-secondary dark:text-gray-200"> Swapee has a simple REST API that can be used to register accounts and make payments and queries. </p> - <h2 class="text-2xl">API Base URL</h2> - <div class="bg-black text-white rounded-lg p-4 flex gap-4"> + <h2 class="text-3xl font-semibold f_bebas_neue tracking-[0.2rem]">API Base URL</h2> + <div class="bg-stone-900 dark:bg-stone-800 text-white rounded-lg p-4 px-5 flex gap-4"> <div>{api}</div> <button class="ml-auto my-auto invert opacity-90" on:click={() => copy(api)} ><Icon icon="copy" style="w-10 max-w-none" /></button > </div> - <h2 class="text-2xl">Auth Token</h2> - <p class="text-secondary"> + <h2 class="text-3xl font-semibold f_bebas_neue tracking-[0.2rem]">Auth Token</h2> + <p class="text-secondary dark:text-gray-200"> {#if user && token} This token authorizes you to use the API as <b>{user.username}</b>. {:else} @@ -42,7 +42,7 @@ Save it in a variable called <b>$token</b> to run the examples. </p> - <div class="bg-black text-white rounded-lg p-4 flex gap-4"> + <div class="bg-stone-900 dark:bg-stone-800 text-white rounded-lg p-4 px-5 flex gap-4"> <div class="w-full break-all">{tokenSample}</div> <button class="ml-auto my-auto invert opacity-90" @@ -51,20 +51,20 @@ > </div> - <h2 class="text-2xl">POST /register</h2> - <p class="text-secondary"> + <h2 class="text-3xl font-semibold f_bebas_neue tracking-[0.2rem]">POST /register</h2> + <p class="text-secondary dark:text-gray-200"> Register a new user account with a username and password </p> <Code sample="register" /> - <h2 class="text-2xl">POST /login</h2> - <p class="text-secondary">Login to an account to get its auth token</p> + <h2 class="text-3xl font-semibold f_bebas_neue tracking-[0.2rem]">POST /login</h2> + <p class="text-secondary dark:text-gray-200">Login to an account to get its auth token</p> <Code sample="login" /> - <h2 class="text-2xl">POST /invoice</h2> - <p class="text-secondary">Create an invoice.</p> + <h2 class="text-3xl font-semibold f_bebas_neue tracking-[0.2rem]">POST /invoice</h2> + <p class="text-secondary dark:text-gray-200">Create an invoice.</p> - <div class="text-secondary"> + <div class="text-secondary dark:text-gray-200"> <div>Request params</div> <div class="grid grid-cols-3 ml-2"> <div class="font-bold">type</div> @@ -93,28 +93,28 @@ <p>Specify a webhook to be called when an invoice is paid</p> <Code sample="webhook" /> - <h2 class="text-2xl">GET /invoice/:hash</h2> - <p class="text-secondary"> + <h2 class="text-3xl font-semibold f_bebas_neue tracking-[0.2rem]">GET /invoice/:hash</h2> + <p class="text-secondary dark:text-gray-200"> Fetch an invoice by passing a bitcoin address or lightning payment hash </p> <Code sample="fetchInvoice" /> - <h2 class="text-2xl">POST /payments</h2> - <p class="text-secondary">Send a lightning payment</p> + <h2 class="text-3xl font-semibold f_bebas_neue tracking-[0.2rem]">POST /payments</h2> + <p class="text-secondary dark:text-gray-200">Send a lightning payment</p> <Code sample="lightning" /> - <p class="text-secondary">Send a bitcoin payment</p> + <p class="text-secondary dark:text-gray-200">Send a bitcoin payment</p> <Code sample="bitcoin" /> - <p class="text-secondary">Send an internal payment to another user</p> + <p class="text-secondary dark:text-gray-200">Send an internal payment to another user</p> <Code sample="internal" /> - <h2 class="text-2xl">GET /payments</h2> - <p class="text-secondary"> + <h2 class="text-3xl font-semibold f_bebas_neue tracking-[0.2rem]">GET /payments</h2> + <p class="text-secondary dark:text-gray-200"> Get all payments sent or received by the current user </p> - <div class="text-secondary"> + <div class="text-secondary dark:text-gray-200"> <div>Query params</div> <div class="grid grid-cols-3 ml-2"> <div class="font-bold">start</div> @@ -129,3 +129,27 @@ </div> <Code sample="payments" /> </div> + +<style> + h2 + p { + margin-top: 0.75rem !important; + } + + h2 { + display: inline-block; + position: relative; + } + + h2::after{ + content: ''; + position: absolute; + bottom: 0; + right: 0; + width: 100%; + left: 50%; + height: 3px; + border-radius: 2px; + background: #7105f3; + transform: translateX(-50%); +} +</style>
\ No newline at end of file diff --git a/src/routes/(static)/privacy/+page.svelte b/src/routes/(static)/privacy/+page.svelte index 4e1e30fa..ffd99f38 100644 --- a/src/routes/(static)/privacy/+page.svelte +++ b/src/routes/(static)/privacy/+page.svelte @@ -1,5 +1,5 @@ -<div class="block space-y-5"> - <h1 class="text-2xl">Privacy Policy</h1> +<div class="block space-y-5 mt-28 md:mt-8"> + <h1 class="text-5xl f_bebas_neue tracking-[0.2rem] font-bold">Privacy Policy</h1> <p> At Swapee.me, creators of the mystical Lightning Wallet, we hold your privacy and personal information in the highest regard. This unique privacy policy outlines our commitment to @@ -65,3 +65,30 @@ these mystifying worlds, for we bear no responsibility for their mystical ways. </p> </div> + +<style> + h2 + p { + margin-top: 0.4rem !important; + margin-bottom: 1rem !important; + } + + h2 { + display: inline-block; + position: relative; + font-weight: 700; + text-transform: uppercase; + } + + /* h2::after{ + content: ''; + position: absolute; + bottom: 0; + right: 0; + width: 100%; + left: 50%; + height: 3px; + border-radius: 2px; + background: #7105f3; + transform: translateX(-50%); + } */ + </style>
\ No newline at end of file diff --git a/src/routes/(static)/sitemap/+page.svelte b/src/routes/(static)/sitemap/+page.svelte new file mode 100644 index 00000000..c1c64da1 --- /dev/null +++ b/src/routes/(static)/sitemap/+page.svelte @@ -0,0 +1,34 @@ +<div class="space-y-5 mt-28 md:mt-8 flex flex-col gap-1 dark:text-red-50"> + <h1 class="text-5xl f_bebas_neue tracking-[0.2rem] font-bold">Sitemap</h1> + <a href="/"> + <h2 class="text-xl">Home</h2> + </a> + <a href="/register"> + <h2 class="text-xl">Register</h2> + </a> + <a href="/login"> + <h2 class="text-xl">Login</h2> + </a> + <a href="/docs"> + <h2 class="text-xl">docs</h2> + </a> + <a href="/privacy"> + <h2 class="text-xl">Privacy</h2> + </a> + <a href="/forgot"> + <h2 class="text-xl">Forgot</h2> + </a> +</div> + +<style> + a { + transition: all 100ms ease-in-out; + } + + a:hover { + color: rgb(113, 5, 243); + text-decoration: underline; + filter: brightness(1.25); + } + +</style>
\ No newline at end of file diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 055c5956..e14911c9 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -1,6 +1,7 @@ <script> import { PUBLIC_DOMAIN } from "$env/static/public"; import "../app.css"; + import "../swapee/css/animation.css"; import { loading, t } from "$lib/translations"; export let data; diff --git a/src/routes/+page.server.js b/src/routes/+page.server.js index 904e543d..aac596a2 100644 --- a/src/routes/+page.server.js +++ b/src/routes/+page.server.js @@ -1,4 +1,27 @@ // export const prerender = true; -export let load = async () => { - return { faqs: ["cost", "compatibility", "safety", "pos", "bitcoin"] }; +import { redirect } from "@sveltejs/kit"; + +export let load = async ({ cookies }) => { + let colorThemeSelected = "dark"; + if (cookies.get("colortheme")) { + colorThemeSelected = cookies.get("colortheme"); + } + + return { faqs: ["cost", "compatibility", "safety", "pos", "bitcoin"], colorThemeSelected: colorThemeSelected }; }; + +export const actions = { + setTheme: async ({ url, cookies }) => { + const theme = url.searchParams.get("theme"); + const redirectTo = url.searchParams.get("redirectTo"); + + if (theme) { + cookies.set("colortheme", theme, { + path: "/", + maxAge: 60 * 60 * 24 * 365, + }); + } + + throw redirect(303, redirectTo ?? "/"); + }, +};
\ No newline at end of file diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 87a933ae..a5ffc3d8 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,6 +1,63 @@ <script> + import { gsap } from "gsap"; + import { enhance } from "$app/forms"; + import * as Accordion from "$lib/shadcn/components/ui/accordion"; + import * as Sheet from "$lib/shadcn/components/ui/sheet"; + import { Button } from "$lib/shadcn/components/ui/button"; + import { Separator } from "$lib/shadcn/components/ui/separator"; + import { page } from '$app/stores'; + import { t } from "$lib/translations"; import { scroll } from '$lib/utils'; - let about, faq; + import ThemeToggle from "../components/buttons/ThemeToggle.svelte"; + import Footer from "../components/Footer.svelte"; + import { browser } from "$app/environment"; + import { onMount } from "svelte"; + + export let data; + let about, faq, s + let askedQuestionsAccordionValue = "item-0" + + let askedQuestionsAccordion = [ + {id: 0, title: "What does it cost?", description: "It's free to register an account and receive payments. We charge a 0.1% conversion fee if you withdraw regular bitcoin to lightning or vice versa."}, + {id: 1, title: "Do I need any special device or software?", description: "It's free to register an account and receive payments. We charge a 0.1% conversion fee if you withdraw regular bitcoin to lightning or vice versa."}, + {id: 2, title: "When do my funds settle?", description: "It's free to register an account and receive payments. We charge a 0.1% conversion fee if you withdraw regular bitcoin to lightning or vice versa."} + ] + + let themeSelected = data.colorThemeSelected; + let toggleThemeForm; + let homeNav; + let homeNavActiveLeft = 32; + let homeNavActiveTranslate = 0; + let NavHowItWorksEl; + + function toggleThemeSelected() { + themeSelected = themeSelected === "light" ? "dark" : "light"; + } + + function submitUpdateTheme ({ action }) { + const theme = action.searchParams.get('theme'); + const htmlClasses = document.documentElement.classList; + if (theme == "dark" && !(htmlClasses.contains("dark"))) { + htmlClasses.add("dark"); + htmlClasses.remove("light"); + } else if (theme == "light" && !(htmlClasses.contains("light"))) { + htmlClasses.add("light"); + htmlClasses.remove("dark"); + } + toggleThemeSelected() + } + + function defineHomeNavActive(element) { + homeNavActiveTranslate = element.getBoundingClientRect().width; + homeNavActiveLeft = element.getBoundingClientRect().left - homeNav.getBoundingClientRect().left + } + + onMount(() => { + if (NavHowItWorksEl) { + defineHomeNavActive(NavHowItWorksEl) + } + }) + </script> <svelte:head> @@ -39,94 +96,140 @@ </div> <!-- nav --> -<nav class="navbar navbar-expand-lg bg-transparent py-3"> - <div class="container-xxl px-lg-5 px-sm-4 px-3"> - <a class="navbar-brand site_logo" href="#"><img src="images/logo.png" alt="" /></a> - <button - class="navbar-toggler border-0 shadow-none" - type="button" - data-bs-toggle="offcanvas" - data-bs-target="#offcanvas" - > - <span class="navbar-toggler-icon" /> - </button> - <div class="offcanvas offcanvas-start flex-lg-row flex-column" id="offcanvas"> - <div class="py-4 pb-5 px-3 d-lg-none d-flex justify-content-end w-100"> - <button type="button" class="btn-close" data-bs-dismiss="offcanvas" aria-label="Close" /> - </div> - <ul class="navbar-nav text-lg-start text-center mx-auto mb-2 mb-lg-0"> - <li class="nav-item me-lg-5 mb-lg-0 mb-4"> - <a class="nav-link active" href="#">How it works</a> +<nav class="navbar navbar-expand-lg dark:bg-black py-3 "> + <div class="container-xxl px-lg-5 px-sm-4 px-3"> + <a class="navbar-brand site_logo max-lg:ml-1" href="#"> + {#if data.colorThemeSelected == "light"} + <img src="images/logo.png" alt="" /> + {:else} + <img src="images/logo-white.png" alt="" /> + {/if} + </a> + <Sheet.Root > + <Sheet.Trigger asChild let:builder> + <Button builders={[builder]} variant="ghost" class="lg:hidden dark:hover:bg-stone-800 px-1"> + <svg class="w-8 h-8 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> + <path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M5 7h14M5 12h14M5 17h14"/> + </svg> + </Button> + </Sheet.Trigger> + <Sheet.Content side="left" id="offcanvas" class="bg-white dark:!bg-black border-r-2 border-black dark:!border-white"> + <ul class=" text-lg-start text-center mx-auto mb-2 dark:text-white mt-16 pl-0"> + <li class="nav-item mb-4"> + <a class="nav-link dark:!text-white" href="#">How it works</a> </li> - <li class="nav-item me-lg-5 mb-lg-0 mb-4"> - <a class="nav-link" href="" on:click={() => scroll(faq)}>F.A.Q.</a> + <li class="nav-item mb-4"> + <a class="nav-link dark:!text-white" href="" on:click={() => scroll(faq)}>F.A.Q.</a> </li> <li class="nav-item"> - <a class="nav-link" href="" on:click={() => scroll(about)}>About</a> + <a class="nav-link dark:!text-white" href="" on:click={() => scroll(about)}>About</a> </li> + </ul> + <div + class="flex flex-wrap items-center gap-4 lg:pt-0 justify-center mt-4" + role="search" + > + <a href="/register" class="btn_black flex-1 w-full text-center text-nowrap"><span class=" dark:!bg-white dark:!text-black dark:!border-black dark:!border-2">get started</span></a> + <a href="/login" class="btn_white flex-1 w-full text-center text-nowrap"><span class=" dark:!bg-black dark:!text-white dark:!border-white dark:!border-2">sign in</span></a> + </div> + <form method="POST" bind:this={toggleThemeForm} use:enhance={submitUpdateTheme} class="mx-auto flex justify-center mt-4" > + {#if themeSelected && themeSelected == "dark"} + <ThemeToggle on:click={toggleThemeSelected} formaction="/?/setTheme&theme=light&redirectTo={$page.url.pathname}" /> + {:else if themeSelected && themeSelected == "light"} + <ThemeToggle on:click={toggleThemeSelected} formaction="/?/setTheme&theme=dark&redirectTo={$page.url.pathname}" /> + {/if} + </form> + </Sheet.Content> + </Sheet.Root> + <div class="hidden lg:flex justify-between items-center !border-r-2 !border-r-white"> + <ul class="flex gap-x-8 relative text-center mx-auto mb-2 dark:text-white uppercase font-semibold" bind:this={homeNav}> + <li class=""> + <a class="text-black dark:!text-white no-underline" href="#" bind:this={NavHowItWorksEl} on:click={(e) => {defineHomeNavActive(e.target)}}>How it works</a> + </li> + <li class=""> + <a class="text-black dark:!text-white no-underline" href="" on:click={(e) => { + defineHomeNavActive(e.target) + scroll(faq) + }}>F.A.Q.</a> + </li> + <li class=""> + <a class="text-black dark:!text-white no-underline" href="" on:click={(e) => { + defineHomeNavActive(e.target) + scroll(faq) + }}>About</a> + </li> + <div class="home-nav-active absolute top-8 h-1 w-10 rounded-sm bg-swapee-purple transition-all duration-300 ease-in-out" style={`left: ${homeNavActiveLeft}px; transform: translate(${(homeNavActiveTranslate / 2) - 20}px, 0px);`}></div> </ul> - <div - class="d-flex justify-content-lg-end justify-content-center nav_btn pt-lg-0 pt-5" - role="search" - > - <a href="/register" class="btn_black"><span>get started</span></a> - <a href="/login" class="btn_white"><span>sign in</span></a> - </div> + </div> + <div + class="hidden lg:flex items-center gap-4 lg:pt-0" + role="search" + > + <a href="/register" class="btn_black"><span class="dark:!bg-white dark:!text-black dark:!border-black dark:!border-2">get started</span></a> + <a href="/login" class="btn_white"><span class="dark:!bg-black dark:!text-white dark:!border-white dark:!border-2">sign in</span></a> + <form method="POST" bind:this={toggleThemeForm} use:enhance={submitUpdateTheme} > + {#if themeSelected && themeSelected == "dark"} + <ThemeToggle on:click={toggleThemeSelected} formaction="/?/setTheme&theme=light&redirectTo={$page.url.pathname}" /> + {:else if themeSelected && themeSelected == "light"} + <ThemeToggle on:click={toggleThemeSelected} formaction="/?/setTheme&theme=dark&redirectTo={$page.url.pathname}" /> + {/if} + </form> </div> </div> </nav> <!-- hero --> -<div class="site_hero pt-md-5 pt-4"> - <div class="container-lg px-sm-4 px-3 pt-md-5 text-center"> +<div class="site_hero pt-md-5 pt-4 dark:bg-black"> + <div class="container-lg px-sm-4 px-3 pt-md-5 mb-16 text-center"> <h1 - class="text-center text-black f_bebas_neue text-uppercase fw-bold letter_space_2 display-3 lh-1" + class="text-center dark:text-white f_bebas_neue text-uppercase fw-bold letter_space_2 display-3 lh-1" > The easiest way to get <br /> started with bitcoin. </h1> - <p class="text-center txt_slate_blue mb-4"> + <p class="text-center txt_slate_blue dark:!text-gray-200 mb-4"> A simple but powerful web wallet for everyone. *No software or hardware required.* </p> <a href="/register" class="btn_purple"><span class="px-5">Start in Seconds</span></a> </div> <div class="container-xxl px-lg-5 px-sm-4 px-3"> <div class="w-100"> - <img class="w-100" src="images/hero_bg.png" alt="" /> + <img src="images/hero_bg.png" alt="" class="w-full slide-top" /> </div> </div> </div> <!-- first grid --> -<section class="py-4"> +<section class="py-4 dark:bg-black"> <div class="container-lg px-sm-4 px-3"> <div class="row justify-content-center"> <div class="col-lg-4 col-md-6 mb-lg-0 mb-4"> <div class="swapee_3_grids h-100 text-center col-md-10 mx-auto"> - <img src="images/swapee-grid-1-3.png" alt="" /> - <h5 class="f_bebas_neue fw-bold letter_space_1">Create your account</h5> - <p class="txt_slate_blue lh-base"> + <img src="images/swapee-grid-1-3.png" class="mx-auto hover:scale-[1.025] transition-all duration-500 ease-in-out" alt="" /> + <h5 class="f_bebas_neue fw-bold letter_space_1 dark:text-white">Create your account</h5> + <p class="txt_slate_blue dark:!text-gray-200 lh-base max-w-[425px] mx-auto"> A username and password is all you need to get started. <a href="#" - class="swapee_grid_link">Don’t forget it!</a + class="swapee_grid_link dark:!text-gray-200">Don’t forget it!</a > </p> </div> + </div> <div class="col-lg-4 col-md-6 mb-lg-0 mb-4"> <div class="swapee_3_grids h-100 text-center col-md-10 mx-auto"> - <img src="images/swapee-grid-2-3.png" alt="" /> - <h5 class="f_bebas_neue fw-bold letter_space_1">Ask for payments</h5> - <p class="txt_slate_blue lh-base"> + <img src="images/swapee-grid-2-3.png" class="mx-auto hover:scale-[1.025] transition-all duration-500 ease-in-out" alt="" /> + <h5 class="f_bebas_neue fw-bold letter_space_1 dark:text-white">Ask for payments</h5> + <p class="txt_slate_blue dark:!text-gray-200 lh-base max-w-[425px] mx-auto"> It’s the same as you normally would traditionally, but with bitcoin. </p> </div> </div> <div class="col-lg-4 col-md-6"> <div class="swapee_3_grids h-100 text-center col-md-10 mx-auto"> - <img src="images/swapee-grid-3-3.png" alt="" /> - <h5 class="f_bebas_neue fw-bold letter_space_1">That's all!</h5> - <p class="txt_slate_blue lh-base"> + <img src="images/swapee-grid-3-3.png" class="mx-auto hover:scale-[1.025] transition-all duration-500 ease-in-out" alt="" /> + <h5 class="f_bebas_neue fw-bold letter_space_1 dark:text-white">That's all!</h5> + <p class="txt_slate_blue dark:!text-gray-200 lh-base max-w-[425px] mx-auto"> Spend your coins immediately or save it and watch it grow, the choice is yours. </p> </div> @@ -136,62 +239,62 @@ </section> <!-- lightning network --> -<section class="pt-md-5" bind:this={about}> +<section class="pt-md-5 dark:bg-black" bind:this={about}> <div class="container-lg px-sm-4 px-3"> <div class="row align-items-center justify-content-center flex-md-row flex-column-reverse"> <div class="col-md-7 mb-md-0 mb-4"> <div> <h6 class="f_bebas_neue txt_purple">Say Goodbye to Waiting</h6> - <h2 class="h1 letter_space_2 f_bebas_neue fw-bold text-black br_md_none mb-3 lh-1"> + <h2 class="h1 letter_space_2 f_bebas_neue fw-bold dark:text-white br_md_none mb-3 lh-1"> Lightning Network <br /> Brings Instant Payments </h2> - <p class="txt_slate_blue"> + <p class="txt_slate_blue dark:!text-gray-200"> Say goodbye to the headaches of waiting for bank settlements and dealing with chargebacks with our payment solution. With instant settlement and no 3% credit card processing fees, merchants can enjoy hassle-free retail payments. </p> - <div class="mt-4 sec_btn"> - <a href="#" class="btn_white f_bebas_neue"><span>Learn More</span></a> - <a href="#" class="btn_black f_bebas_neue"><span>Get Started</span></a> + <div class="mt-4 sec_btn flex gap-x-3 gap-y-3 flex-wrap"> + <a href="#" class="btn_white f_bebas_neue"><span class="dark:!bg-black dark:!text-white dark:!border-white dark:!border-2">Learn More</span></a> + <a href="/register" class="btn_black f_bebas_neue"><span class="dark:!bg-white dark:!text-black dark:!border-black dark:!border-2">Get Started</span></a> </div> </div> </div> - <div class="col-md-5 mb-md-0 mb-5 scale_img_right"> + <div class="col-md-5 mb-md-0 mb-5 scale_img_rig"> <div> - <img src="images/swapee-sec-calculator.png" class="w-100" alt="" /> + <img src={data.colorThemeSelected == "light" ? "images/swapee-sec-calculator.png" : "images/swapee-sec-calculator-dark.png"} class="hover:scale-[1.015] transition-all duration-500 ease-in-out" alt="" /> </div> </div> </div> </div> </section> -<section class="pt-5 bg_light"> +<section class="pt-5 bg_light dark:!bg-[#0D0D0D]"> <div class="container-lg px-sm-4 px-3"> <div class="row align-items-center justify-content-center"> - <div class="col-md-5 scale_img_left"> + <div class="col-md-5"> <div> - <img src="images/swapee-sec-2-img.png" class="w-100" alt="" /> + <img src="images/swapee-sec-2-img.png" class="slide-top" alt="" /> </div> </div> <div class="col-md-7 mb-md-0 mb-4"> <div> <h6 class="f_bebas_neue txt_purple">Quick and painless</h6> - <h2 class="h1 f_bebas_neue fw-bold text-black br_md_none mb-3 letter_space_2 lh-1"> - Simple to use + <h2 class="h1 f_bebas_neue fw-bold dark:text-white br_md_none mb-3 letter_space_2 lh-1"> + Simple to uses </h2> - <p class="txt_slate_blue mb-4"> + <p class="txt_slate_blue dark:!text-gray-200 mb-4"> Just enter an amount in your local currency, share the QR code and you’re done. We do all the heavy lifting so you can focus on your business. You always have the option of taking custody of your funds by withdrawing instantly at any time. </p> - <div class="mt-4 sec_btn"> - <a href="#" class="btn_white f_bebas_neue"><span>Learn More</span></a> - <a href="/register" class="btn_purple f_bebas_neue"><span>Get Started</span></a> + <div class="mt-4 sec_btn flex gap-x-3 gap-y-3 flex-wrap"> + <a href="#" class="btn_white f_bebas_neue"><span >Learn More</span></a> + <a href="/register" class="btn_purple f_bebas_neue"><span >Get Started</span></a> </div> </div> </div> @@ -199,116 +302,74 @@ </div> </section> -<section class="sec_3 position-relative"> +<section class="sec_3 position-relative dark:bg-black"> <div class="col-md-5 d-xxl-none d-md-block d-none position-absolute img_position"> <div> - <img src="images/swapee-sec-3-img.png" class="w-100" alt="" /> + <img src={data.colorThemeSelected == "light" ? "images/swapee-sec-3-img.png" : "images/swapee-sec-3-img-dark.png"} alt="" class="hover:scale-[0.985] transition-all duration-500 ease-in-out" /> </div> </div> <div class="container-lg px-sm-4 px-3"> <div class="row align-items-center justify-content-center flex-md-row flex-column-reverse"> - <div class="col-md-6 mb-md-0 mb-4"> + <div class="col-md-6 mb-md-0"> <div> <h6 class="f_bebas_neue txt_purple">Customized & Personalized</h6> - <h2 class="h1 letter_space_2 f_bebas_neue fw-bold text-black br_md_none mb-3 lh-1"> + <h2 class="h1 letter_space_2 f_bebas_neue fw-bold dark:text-white br_md_none mb-3 lh-1"> Brand it your way! </h2> - <p class="txt_slate_blue"> + <p class="txt_slate_blue dark:!text-gray-200"> You have complete control over your profile page's aesthetic. Customize it with your preferred color scheme, avatar, and banner to reflect your brand, personality and interests. </p> - <div class="mt-4 sec_btn"> - <a href="#" class="btn_white f_bebas_neue mb-3"><span>Learn More</span></a> - <a href="#" class="btn_black f_bebas_neue mb-3"><span>Get Started</span></a> + <div class="sec_btn mt-4 flex gap-x-3 flex-wrap"> + <a href="#" class="btn_white f_bebas_neue mb-3"><span class="dark:!bg-black dark:!text-white dark:!border-white dark:!border-2">Learn More</span></a> + <a href="/register" class="btn_black f_bebas_neue mb-3"><span class="dark:!bg-white dark:!text-black dark:!border-black dark:!border-2">Get Started</span></a> </div> </div> </div> - <div class="col-md-6 mb-md-0 mb-4 sec_3_img"> + <div class="col-md-6 mb-md-0 mb-4 overflow-hidden"> <div class="d-xxl-block d-md-none d-block"> - <img src="images/swapee-sec-3-img.png" class="w-100" alt="" /> + <img src={data.colorThemeSelected == "light" ? "images/swapee-sec-3-img.png" : "images/swapee-sec-3-img-dark.png"} alt="" class="hover:scale-[0.985] transition-all duration-500 ease-in-out" /> </div> </div> </div> </div> </section> -<section class="py-5 bg_light"> +<section class="py-5 bg_light dark:!bg-[#0D0D0D]"> <div class="container-lg px-sm-4 px-3" bind:this={faq}> <div class="row align-items-center justify-content-center"> <div class="col-12 text-center"> <h6 class="f_bebas_neue txt_purple">This might help</h6> - <h2 class="h1 letter_space_2 f_bebas_neue fw-bold text-black br_md_none mb-5 lh-1"> + <h2 class="h1 letter_space_2 f_bebas_neue fw-bold dark:text-white br_md_none mb-5 lh-1"> Frequently asked <br /> questions </h2> </div> - <div class="accordion" id="accordionExample"> - <div class="accordion-item swapee_accordion"> - <h2 class="" id="headingOne"> - <button class="accordion-button shadow-none" type="button"> - <span class="line"> What does it cost? </span> - </button> - </h2> - <div id="collapseOne"> - <div class="accordion-body"> - <p class="txt_slate_blue"> - Registering an account and receiving payments on Swapee.me is completely free. Our - aim is to offer a smooth user experience without any financial barriers. However, - when converting regular Bitcoin to Lightning or vice versa, we apply a modest 0.1% - conversion fee to ensure secure and efficient transactions. - </p> - </div> - </div> - </div> - - <div class="accordion-item swapee_accordion"> - <h2 class="accordion-header" id="headingTwo"> - <button class="accordion-button shadow-none" type="button"> - <span class="line"> Do I need any special device or software? </span> - </button> - </h2> - <div id="collapseTwo"> - <div class="accordion-body"> - <p class="txt_slate_blue"> - No, Swapee.me is designed to be incredibly user-friendly. You can access our - platform using any device that can connect to a web browser - whether it's your - mobile phone, PC, tablet, or any other compatible device. Swapee.me prioritizes - accessibility and ease of use for all users, regardless of their chosen device. - </p> - </div> - </div> - </div> - - <div class="accordion-item swapee_accordion"> - <h2 class="accordion-header" id="headingThree"> - <button class="accordion-button shadow-none " type="button"> - <span class="line"> When do my funds settle? </span> - </button> - </h2> - <div id="collapseThree" aria-labelledby="headingThree" data-bs-parent="#accordionExample"> - <div class="accordion-body"> - <p class="txt_slate_blue"> - At Swapee.me, we value your time. Lightning payments on our platform settle - instantly, reflecting our commitment to efficiency and user satisfaction. Forget - waiting for extended transaction confirmations; with Swapee.me, you can experience - the speed and efficiency of the Lightning Network firsthand. - </p> - </div> - </div> - </div> - </div> + <Accordion.Root class="w-full flex flex-col gap-3" bind:value={askedQuestionsAccordionValue} > + {#each askedQuestionsAccordion as askedQuestionAccordion } + <Accordion.Item value={`item-${askedQuestionAccordion.id}`} class="bg-white dark:!bg-black rounded-[10px] border-[1px] border-gray-300 px-4"> + <Accordion.Trigger class="py-0"> + <h2 class="text-base pt-3 pb-3 font-bold border-b-black dark:!border-b-swapee-purple {askedQuestionsAccordionValue == `item-${askedQuestionAccordion.id}` ? 'border-b-2' : ''}">{askedQuestionAccordion.title}</h2> + </Accordion.Trigger> + <Accordion.Content class="text-base text-slate-500 dark:text-gray-200 mt-0"> + <Separator orientation="horizontal" class="mt-0 mb-3 bg-purple-950" /> + <p class="mb-0">{askedQuestionAccordion.description}</p> + </Accordion.Content> + </Accordion.Item> + {/each} + </Accordion.Root> </div> </div> </section> <!-- bitcoin_location --> -<div class="bitcoin_location"> +<div class="bitcoin_location dark:bg-black bg-map-light dark:!bg-map-dark bg-no-repeat"> <div class="container-lg px-sm-4 px-3"> - <h2 class="h3 text-center text-black f_bebas_neue fw-bold letter_space_2"> + <h2 class="h3 text-center dark:text-white f_bebas_neue fw-bold letter_space_2"> Real-World Bitcoin Locations </h2> <p class="text-center opacity-75 mb-md-5 mb-4"> @@ -317,56 +378,14 @@ with <span class="fs_18 fw-bold">Swapee!</span> </p> <div class="d-flex justify-content-center align-items-start flex-wrap"> - <a href="#" class="btn_line me-sm-3 me-2 mb-4">Business Listings</a> - <a href="#" class="btn_black"><span class="px-sm-5">Get Listed</span></a> + <a href="#" class="btn_line me-sm-3 me-2 mb-4 dark:!text-white">Business Listings</a> + <a href="#" class="btn_black"><span class="px-sm-5 dark:!bg-white dark:!text-black dark:!border-black dark:!border-2">Get Listed</span></a> </div> </div> </div> -<!-- footer --> -<footer class="site_footer"> - <div class="container-lg px-4"> - <!-- footer_top --> - <div class="footer_top pb-4"> - <div class="row align-items-center justify-content-between"> - <div class="col-md-5 mb-md-0 mb-5"> - <a href="#" class="footer_logo"><img src="images/footer-logo.png" alt="" /></a> - <!-- <p class="text-white-50 mt-5 mb-4"> --> - <!-- Copyright © 2023. Swapee.me is a Registered Cryptoasset firm and is registered with the --> - <!-- UK Financial Conduct Authority. --> - <!-- <br /> --> - <!-- <br /> --> - <!-- All rights reserved. --> - <!-- </p> --> - <a class="btn_language" href="#">English</a> - </div> - <div - class="ps-md-4 footer_top_right col-md-6 d-flex align-items-center justify-content-end justify-content-sm-center justify-content-between" - > - <div class="row justify-content-md-end"> - <div class="col-sm-6 mb-xl-0 mb-4 pe-md-0 pe-sm-5"> - <h6 class="text-white opacity-75 mb-0">Business enquiries</h6> - <a href="mailto:[email protected]">[email protected]</a> - </div> - <div class="col-sm-6 pe-xl-5 mb-4 pe-md-0 pe-sm-5"> - <h6 class="text-white opacity-75 mb-0">Support enquiries</h6> - <a href="mailto:[email protected]">[email protected]</a> - </div> - </div> - </div> - </div> +<Footer /> - <!-- footer_bottom --> - <div class="footer_bottom pt-4 pb-2"> - <ul class="list-unstyled mb-0 ps-0"> - <li class="pb-3"> - <a href="/docs">Documentation</a> - </li> - <li class="pb-3"> - <a href="/privacy">Privacy Policy</a> - </li> - </ul> - </div> - </div> - </div> -</footer> +<style> + +</style>
\ No newline at end of file diff --git a/src/swapee/css/animation.css b/src/swapee/css/animation.css new file mode 100644 index 00000000..4ef62b82 --- /dev/null +++ b/src/swapee/css/animation.css @@ -0,0 +1,32 @@ +/* ---------------------------------------------- + * Generated by Animista on 2024-2-6 22:17:3 + * Licensed under FreeBSD License. + * See http://animista.net/license for more info. + * w: http://animista.net, t: @cssanimista + * ---------------------------------------------- */ + + @-webkit-keyframes slide-top { + 0% { + -webkit-transform: translateY(0) scale(1.015); + transform: translateY(0) scale(1.015); + } + 100% { + -webkit-transform: translateY(-20px); + transform: translateY(-20px); + } + } + @keyframes slide-top { + 0% { + -webkit-transform: translateY(0) scale(1.015); + transform: translateY(0) scale(1.015); + } + 100% { + -webkit-transform: translateY(-20px); + transform: translateY(-20px); + } +} + +.slide-top { + -webkit-animation: slide-top 4s infinite alternate cubic-bezier(0.250, 0.460, 0.450, 0.940) both; + animation: slide-top 4s infinite alternate cubic-bezier(0.250, 0.460, 0.450, 0.940) both; +}
\ No newline at end of file diff --git a/src/swapee/css/style.css b/src/swapee/css/style.css index 69996058..06633f62 100644 --- a/src/swapee/css/style.css +++ b/src/swapee/css/style.css @@ -91,7 +91,6 @@ body{ #offcanvas ul li a{ font-size: 14px; font-weight: 600; - color: var(--bs-black); text-transform: uppercase; font-family: 'Work Sans', sans-serif; position: relative; @@ -104,7 +103,7 @@ body{ left: 50%; width: 0; height: 2px; - background: #7005f38a; + background: #7105f3; transform: translateX(-50%); -webkit-transform: translateX(-50%); -moz-transform: translateX(-50%); @@ -117,7 +116,6 @@ body{ -o-transition: var(--transition_3s); } -#offcanvas ul li a.active::after, #offcanvas ul li a:hover::after{ width: 50px; } @@ -231,7 +229,7 @@ body{ align-items: center; padding-top: 90px; padding-bottom: 90px; - background: url("../img/map.png") no-repeat; + background: url("../img/footer-logo.png") no-repeat; background-size: cover; } @@ -313,7 +311,7 @@ body{ padding-bottom: 12vw; } -/* accordion */ +/* accordion NOT MORE BEING USED (AFTER ALTERATIONS, NOW THE ACCORDION IS BUILT WITH TAILWIND + SHADCN) */ .swapee_accordion { border-radius: 10px; -webkit-border-radius: 10px; diff --git a/src/swapee/img/map-dark.png b/src/swapee/img/map-dark.png Binary files differnew file mode 100644 index 00000000..08a00dd5 --- /dev/null +++ b/src/swapee/img/map-dark.png |
