aboutsummaryrefslogtreecommitdiffstats
path: root/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'src/components')
-rw-r--r--src/components/404.svelte16
-rw-r--r--src/components/About.svelte73
-rw-r--r--src/components/AppHeader.svelte88
-rw-r--r--src/components/Footer.svelte39
-rw-r--r--src/components/LandingHeader.svelte106
-rw-r--r--src/components/LandingHero.svelte21
-rw-r--r--src/components/LoadingSplash.svelte7
-rw-r--r--src/components/RegisterOrLogin.svelte43
-rw-r--r--src/components/index.js4
9 files changed, 343 insertions, 54 deletions
diff --git a/src/components/404.svelte b/src/components/404.svelte
new file mode 100644
index 00000000..503316bb
--- /dev/null
+++ b/src/components/404.svelte
@@ -0,0 +1,16 @@
+<script>
+ import { Icon } from '$comp';
+</script>
+
+<div class="flex justify-center items-center mt-20">
+ <div class="space-y-5 text-center">
+ <a href="/">
+ <Icon icon="logo" />
+ </a>
+
+ <Icon icon="question" style="mx-auto w-full" />
+
+ <h1 class="font-bold text-5xl">404</h1>
+ <p>Page not found.</p>
+ </div>
+</div>
diff --git a/src/components/About.svelte b/src/components/About.svelte
new file mode 100644
index 00000000..3731bf9b
--- /dev/null
+++ b/src/components/About.svelte
@@ -0,0 +1,73 @@
+<script>
+ import { Image, Icon } from '$comp';
+
+ const aboutAdam = [
+ 'Running Bitcoin since 2011',
+ '20+ years web development experience in government and industry',
+ 'Early Bitcoin Vancouver meetup organizer',
+ 'Founder of The Bitcoin Co-op and early supporter of Decentral Vancouver',
+ 'Yogi, permaculturist, anarchist, decentralist',
+ 'Husband, father, brother, son'
+ ];
+</script>
+
+<h3 class="text-5xl font-medium mb-10 text-center">About</h3>
+<div
+ class="md:px-10 lg:px-0 block lg:flex justify-center text-secondary text-xl lg:space-x-20 mx-auto max-w-7xl relative"
+>
+ <p class="w-full lg:w-5/12">
+ <strong>CoinOS is</strong> an <strong>open source</strong> bitcoin web wallet, point of sale,
+ ecommerce marketplace and exchange platform. Development started in Vancouver in September 2012
+ as a way to provide local merchants with a convenient way to accept bitcoin payments.
+ <br /><br />
+ The feature set has grown over the years to accomodate a wide variety of use cases with the goal
+ of making it as easy as possible for anyone to get started using Bitcoin quickly, cheaply, and securely.
+ <br /><br />
+ </p>
+ <p class="w-full lg:w-5/12">
+ Anyone can download the source code and host their own instance of the platform backed by their
+ own bitcoin, liquid or lightning nodes, or reach out and we'll gladly set this up for you.
+ <br /><br />
+ Intra-account transfers between custodial wallets of different users on our server are completely
+ free, instant, and unlimited.
+ </p>
+ <Image image="swoosh" style="w-32 absolute -bottom-20 lg:bottom-0 right-0 md:right-10" />
+</div>
+
+<div class="px-5 block lg:flex justify-center lg:space-x-32 items-center mt-40 lg:mt-20">
+ <div class="space-y-5 mb-5 lg:mb-0">
+ <h3 class="text-5xl font-medium mb-10 text-center lg:text-right">The Founder</h3>
+
+ <Image image="adam" style="rounded-full mx-auto lg:mx-0 lg:ml-auto w-40" />
+
+ <div class="space-y-2">
+ <span class="text-2xl text-center font-semibold block lg:text-right">Adam Soltys</span>
+ <span class="text-xl text-center text-secondary block lg:text-right"
+ >Chief Technical Officer</span
+ >
+ </div>
+
+ <div class="flex justify-center lg:justify-end items-center space-x-5">
+ <a
+ href="https://twitter.com/adamsoltys"
+ target="_blank"
+ rel="noreferrer"
+ class="rounded-full p-2 bg-[#1D9BF0]"><Icon icon="twitter" style="w-6" /></a
+ >
+ <a
+ href="https://github.com/asoltys"
+ target="_blank"
+ rel="noreferrer"
+ class="rounded-full p-2 bg-gray-800"><Icon icon="github" style="w-6" /></a
+ >
+ </div>
+ </div>
+
+ <ul
+ class="w-full mx-auto md:w-[700px] lg:w-[500px] xl:w-auto text-secondary px-1 md:px-10 text-xl list-disc space-y-5"
+ >
+ {#each aboutAdam as about}
+ <li>{about}</li>
+ {/each}
+ </ul>
+</div>
diff --git a/src/components/AppHeader.svelte b/src/components/AppHeader.svelte
index 249e2826..242e6924 100644
--- a/src/components/AppHeader.svelte
+++ b/src/components/AppHeader.svelte
@@ -1,32 +1,88 @@
<script>
// we will want to dynamically use the users avatar on this screen if they have uploaded one
+ import { user } from '$lib/store';
import { goto } from '$app/navigation';
import { Icon, LocaleSelector } from '$comp';
- import { locale, locales } from 'svelte-i18n';
+ export let avatarPosition = 'left-[calc(50vw-48px)]';
+
+ const menuButtons = [
+ { title: 'Customers', icon: 'customers', goto: 'customers' },
+ { title: 'Dashboard', icon: 'dash', goto: 'dashboard' },
+ { title: 'Settings', icon: 'settings', goto: 'settings' },
+ { title: 'Support', icon: 'support', goto: 'support' },
+ { title: 'Sign out', icon: 'logout', goto: 'logout' }
+ ];
+
+ let showMenu = false;
+
+ const handleMenuItemClick = (item) => {
+ if (item === 'logout') {
+ goto('/logout');
+ } else {
+ goto(`/${$user.username + '/' + item}`);
+ }
+ };
</script>
-<header class="bg-gradient-to-r from-primary to-gradient h-[20vh] w-full relative">
+<header class="bg-gradient-to-r from-primary to-gradient h-[175px] w-full relative">
<nav class="flex justify-end items-center space-x-4 p-5">
<LocaleSelector />
-
- <button class="bg-white p-2 rounded-full w-12 h-12" on:click={() => goto('/receive')}
- ><Icon icon="numpad" style="mx-auto" /></button
- >
- <button class="bg-white p-2 rounded-full w-12 h-12"
- ><Icon icon="clock" style="mx-auto" /></button
- >
- <button class="bg-white p-2 rounded-full w-12 h-12"
- ><Icon icon="menu" style="mx-auto" /></button
- >
- <button class="bg-white p-2 rounded-full w-12 h-12"
- ><Icon icon="profile" style="mx-auto" /></button
- >
+ {#if $user}
+ <a href={`/${$user.username}/receive`}>
+ <button class="bg-white p-2 rounded-full w-12 h-12"
+ ><Icon icon="numpad" style="mx-auto" />
+ </button>
+ </a>
+ <a href={`/${$user.username}/transactions`}>
+ <button class="bg-white p-2 rounded-full w-12 h-12"
+ ><Icon icon="clock" style="mx-auto" />
+ </button>
+ </a>
+ <a href={`/${$user.username}`}>
+ <button class="bg-white p-2 rounded-full w-12 h-12"
+ ><Icon icon="profile" style="mx-auto" />
+ </button>
+ </a>
+ <div class="relative">
+ <button class="bg-white p-2 rounded-full w-12 h-12" on:click={() => (showMenu = !showMenu)}
+ ><Icon icon="menu" style="mx-auto" />
+ </button>
+ <div
+ class="{showMenu
+ ? 'block'
+ : 'hidden'} absolute top-14 right-0 bg-white rounded-3xl p-8 shadow-xl z"
+ >
+ <ul class="space-y-5 w-32">
+ {#each menuButtons as button}
+ <li>
+ <button
+ class="flex justify-center items-center font-semibold text-sm"
+ on:click={() => handleMenuItemClick(button.goto)}
+ ><Icon icon={button.icon} style="mr-1" /> {button.title}
+ </button>
+ </li>
+ {/each}
+ </ul>
+ </div>
+ </div>
+ {:else}
+ <a href="/login">
+ <button class="bg-white px-5 py-2 rounded-xl font-semibold text-sm">Sign in </button>
+ </a>
+ {/if}
+>>>>>>> master
</nav>
<div
- class="absolute top-[calc(20vh-48px)] left-[calc(50vw-48px)] rounded-full border-4 border-white p-4 bg-gradient-to-r from-primary to-gradient w-24 h-24"
+ class="absolute top-[calc(175px-48px)] {avatarPosition} rounded-full border-4 border-white p-4 bg-gradient-to-r from-primary to-gradient w-24 h-24"
>
<Icon icon="logo-symbol-white" style="mx-auto" />
</div>
</header>
+
+<style>
+ .z {
+ z-index: 100;
+ }
+</style>
diff --git a/src/components/Footer.svelte b/src/components/Footer.svelte
new file mode 100644
index 00000000..0c682179
--- /dev/null
+++ b/src/components/Footer.svelte
@@ -0,0 +1,39 @@
+<script>
+ import { Icon } from '$comp';
+
+ const followLinks = [
+ { url: 'https://twitter.com/coinoswallet', title: 'Twitter' },
+ { url: 'https://github.com/coinos', title: 'GitHub' },
+ { url: 'https://t.me/coinos', title: 'Telegram' }
+ ];
+
+ const companyLinks = [
+ { url: 'mailto:[email protected]', title: 'Support' },
+ { url: '/community', title: 'Community' },
+ { url: '/jobs', title: 'Jobs' }
+ ];
+</script>
+
+<footer class="space-y-10 md:space-y-0 text-xl block md:flex justify-around items-center mb-20">
+ <Icon icon="logo" style="w-48 mx-auto md:mx-0" />
+
+ <div class="text-center md:text-left">
+ <p class="font-semibold">Follow Us</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">{link.title}</a></li>
+ {/each}
+ </ul>
+ </div>
+
+ <div class="text-center md:text-left">
+ <p class="font-semibold">Company</p>
+ <ul class="mt-5 text-secondary space-y-3">
+ {#each companyLinks as link}
+ <li><a href={link.url}>{link.title}</a></li>
+ {/each}
+ </ul>
+ </div>
+
+ <Icon icon="shield" style="mx-auto md:mx-0" />
+</footer>
diff --git a/src/components/LandingHeader.svelte b/src/components/LandingHeader.svelte
index ca9d431e..352b200c 100644
--- a/src/components/LandingHeader.svelte
+++ b/src/components/LandingHeader.svelte
@@ -2,34 +2,112 @@
import { goto } from '$app/navigation';
import { scroll } from '$lib/utils';
import { Icon, LocaleSelector } from '$comp';
-
- import { _, locale, locales } from 'svelte-i18n';
+ import { user } from '$lib/store';
+ import { _ } from 'svelte-i18n';
export let howItWorks;
export let faq;
+ export let about;
+
+ let showMobileMenu = false;
+ const mobileMenuButtonClick = (section) => {
+ showMobileMenu = false;
+ scroll(section);
+ };
</script>
-<header class="w-full lg:w-5/6 pt-10 mx-auto">
+<header
+ class="w-full lg:w-5/6 py-5 xl:pb-0 xl:pt-10 mx-auto fixed md:sticky z-10 top-0 bg-white/90"
+>
<nav class="block xl:flex flex-wrap justify-between items-center">
- <a href="/">
+ <a href="/" class="hidden md:block">
<Icon icon="logo" style="mx-auto mb-5 xl:mb-0" />
</a>
+ <Icon icon="logo" style="block md:hidden ml-5 w-48" />
<LocaleSelector />
+ <!-- desktop nav -->
<div class="hidden space-x-10 md:flex flex-wrap justify-center items-center font-bold">
<button on:click={() => scroll(howItWorks)}>{$_('howItWorks')}</button>
<button on:click={() => scroll(faq)}>{$_('FAQ')}</button>
- <button>{$_('about')}</button>
- <button class="border rounded-full px-6 py-2 font-bold" on:click={() => goto('/register')}
- >{$_('startInSeconds')}</button
- >
- <button
- class="bg-black text-white border rounded-full px-6 py-2 font-bold"
- on:click={() => goto('/login')}
- >
- {$_('signIn')}
- </button>
+ <button on:click={() => scroll(about)}>{$_('about')}</button>
+ {#if !$user}
+ <button class="border rounded-full px-6 py-2 font-bold" on:click={() => goto('/register')}
+ >{$_('startInSeconds')}
+ </button>
+ <button
+ class="bg-black text-white border rounded-full px-6 py-2 font-bold"
+ on:click={() => goto('/login')}
+ >
+ {$_('signIn')}
+ </button>
+ {:else}
+ <button
+ class="border rounded-full px-6 py-2 font-bold"
+ on:click={() => goto(`/${$user.username}/dashboard`)}
+ >Account
+ </button>
+ <button
+ class="bg-black text-white border rounded-full px-6 py-2 font-bold"
+ on:click={() => goto('/logout')}
+ >
+ Sign out
+ </button>
+ {/if}
+ </div>
+
+ <!-- mobile nav -->
+ <button
+ class="block md:hidden absolute top-[34.5px] right-10 z"
+ on:click={() => (showMobileMenu = !showMobileMenu)}
+ ><Icon icon={!showMobileMenu ? 'menu' : 'close'} />
+ </button>
+
+ <div
+ class="block md:hidden absolute top-0 {showMobileMenu
+ ? 'right-0'
+ : 'right-[-100%]'} transition-all ease-in-out duration-300 h-[100vh] w-full bg-white"
+ >
+ <div class="space-y-8 mt-24 ml-10 font-bold text-xl">
+ <button on:click={() => mobileMenuButtonClick(howItWorks)} class="block"
+ >{$_('howItWorks')}</button
+ >
+ <button on:click={() => mobileMenuButtonClick(faq)} class="block">{$_('FAQ')}</button>
+ <button on:click={() => mobileMenuButtonClick(about)} class="block">{$_('about')}</button>
+ {#if !$user}
+ <button
+ class="border rounded-full px-6 py-2 font-bold block"
+ on:click={() => goto('/register')}
+ >{$_('startInSeconds')}
+ </button>
+ <button
+ class="bg-black text-white border rounded-full px-6 py-2 font-bold block"
+ on:click={() => goto('/login')}
+ >
+ {$_('startInSeconds')}
+ </button>
+ {:else}
+ <button
+ class="border rounded-full px-6 py-2 font-bold block"
+ on:click={() => goto(`/${$user.username}/dashboard`)}
+ >Account
+ </button>
+ <button
+ class="bg-black text-white border rounded-full px-6 py-2 font-bold block"
+ on:click={() => goto('/logout')}
+ >
+ Sign out
+ </button>
+ {/if}
+ </div>
+>>>>>>> master
</div>
</nav>
</header>
+
+<style>
+ .z {
+ z-index: 100;
+ }
+</style>
diff --git a/src/components/LandingHero.svelte b/src/components/LandingHero.svelte
index 2c2e1ab5..93bea8c2 100644
--- a/src/components/LandingHero.svelte
+++ b/src/components/LandingHero.svelte
@@ -1,9 +1,10 @@
<script>
import { goto } from '$app/navigation';
import { Icon, Image } from '$comp';
+ import { user } from '$lib/store';
</script>
-<div>
+<div class="mt-[96.88px] md:mt-0">
<div class="space-y-10">
<h1
class="text-5xl md:text-6xl lg:text-7xl 2xl:text-8xl font-medium text-center w-full md:w-3/4 lg:w-1/2 max-w-7xl mx-auto leading-tight"
@@ -19,14 +20,16 @@
Grow your customer base and revenue by accepting Bitcoin with an easy-to-use and managed Point
of Sale. No software or hardware required.
</h2>
- <div class="flex justify-center">
- <button
- class="bg-black text-white border rounded-full px-6 py-2 font-bold"
- on:click={() => goto('/register')}
- >
- Start in Seconds
- </button>
- </div>
+ {#if !$user}
+ <div class="flex justify-center">
+ <button
+ class="bg-black text-white border rounded-full px-6 py-2 font-bold"
+ on:click={() => goto('/register')}
+ >
+ Start in Seconds
+ </button>
+ </div>
+ {/if}
</div>
<!-- hero image -->
diff --git a/src/components/LoadingSplash.svelte b/src/components/LoadingSplash.svelte
new file mode 100644
index 00000000..2ab4c739
--- /dev/null
+++ b/src/components/LoadingSplash.svelte
@@ -0,0 +1,7 @@
+<script>
+ import { Icon } from '$comp';
+</script>
+
+<div class="flex justify-center items-center">
+ <Icon icon="logo" style="mt-[calc(50vh-72px)]" />
+</div>
diff --git a/src/components/RegisterOrLogin.svelte b/src/components/RegisterOrLogin.svelte
index 7cc41709..157c2821 100644
--- a/src/components/RegisterOrLogin.svelte
+++ b/src/components/RegisterOrLogin.svelte
@@ -1,13 +1,15 @@
<script>
+ import { toast } from '@zerodevx/svelte-toast';
import { Icon } from '$comp';
import { post } from '$lib/utils';
- import { token } from '$lib/store';
- import { connect } from '$lib/socket';
+ import { user, token } from '$lib/store';
+ import { auth } from '$lib/socket';
import { goto } from '$app/navigation';
export let page;
- let username, password;
+ let username = 'bob',
+ password = 'pw';
let revealPassword = false;
@@ -16,20 +18,27 @@
'Sign in': '/login'
}[page];
- let submit = () =>
- post(url, { username, password }).then((r) =>
- r.json().then((r) => {
- $token = r.token;
- connect();
- goto('/receive');
- })
- );
+ let submit = async () => {
+ try {
+ let r = await post(url, { username, password });
+ if (!r.token) r = await post('/login', { username, password });
+ $token = r.token;
+ auth();
+ } catch (e) {
+ if (!e.message) e.message = 'Login failed';
+ toast.push(e.message);
+ }
+ };
+
+ $: if ($user) goto(`/${username}/receive`);
</script>
<div class="pt-10">
- <a href="/">
- <Icon icon="logo" style="mx-auto mb-10" />
- </a>
+ <div class="w-[243px] mx-auto mb-10">
+ <a href="/">
+ <Icon icon="logo" />
+ </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]">
@@ -38,11 +47,13 @@
<form class="space-y-5" on:submit|preventDefault={submit}>
<div>
<label for="username" class="font-semibold">Username</label>
+ <!-- svelte-ignore a11y-autofocus -->
<input
type="text"
required
class="bg-primary p-4 rounded-2xl w-full"
bind:value={username}
+ autofocus
/>
</div>
@@ -78,7 +89,9 @@
</p>
{:else}
<div class="flex justify-end items-center">
- <a href="" class="underline underline-offset-4 text-black text-sm">Forgot Password?</a>
+ <a href="/forgot" class="underline underline-offset-4 text-black text-sm"
+ >Forgot Password?</a
+ >
</div>
{/if}
diff --git a/src/components/index.js b/src/components/index.js
index f0e86183..1d5b369d 100644
--- a/src/components/index.js
+++ b/src/components/index.js
@@ -8,3 +8,7 @@ export { default as Image } from './Image.svelte';
export { default as RegisterOrLogin } from './RegisterOrLogin.svelte';
export { default as AppHeader } from './AppHeader.svelte';
export { default as LocaleSelector } from './LocaleSelector.svelte';
+export { default as LoadingSplash } from './LoadingSplash.svelte';
+export { default as PageNotFound } from './404.svelte';
+export { default as About } from './About.svelte';
+export { default as Footer } from './Footer.svelte';