sveltestrap

This commit is contained in:
Ben Allfree 2022-09-19 11:23:06 -07:00
parent 716f379395
commit c8c8e53a10
25 changed files with 553 additions and 396 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
.DS_Store
node_modules
.secret
.vscode

View File

@ -16,6 +16,7 @@
],
"prettier": {
"semi": false,
"useTabs": false,
"singleQuote": true,
"plugins": [
"./node_modules/prettier-plugin-organize-imports",

View File

@ -1 +0,0 @@
export const isBrowser = () => typeof window !== 'undefined'

View File

@ -1,5 +1,5 @@
{
"useTabs": true,
"useTabs": false,
"singleQuote": true,
"semi": false,
"trailingComma": "none",

View File

@ -34,6 +34,7 @@
"sass": "^1.54.9",
"svelte-fa": "^3.0.3",
"svelte-highlight": "^6.2.1",
"sveltestrap": "^5.9.0",
"ts-brand": "^0.0.2"
}
}

View File

@ -3,7 +3,6 @@
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<link rel="stylesheet" href="%sveltekit.assets%/global.css" />
<meta name="viewport" content="width=device-width" />
%sveltekit.head%
</head>

View File

@ -1,9 +1,10 @@
<script lang="ts">
import { isLoggedIn, user } from '@pockethost/common/src/pocketbase'
import Button from './Button/Button.svelte'
import { browser } from '$app/environment'
import { redirect } from '$util/redirect'
import { isLoggedIn } from '@pockethost/common/src/pocketbase'
if (typeof window !== 'undefined' && isLoggedIn()) {
window.location.href = '/dashboard'
if (browser && isLoggedIn()) {
redirect(`/dashboard`)
}
</script>

View File

@ -1,50 +1,22 @@
<script lang="ts">
import { goto } from '$app/navigation'
import { ButtonStyles } from './types'
import { goto } from '$app/navigation'
import { Button } from 'sveltestrap'
import { ButtonStyles } from './types'
export let style: ButtonStyles = ButtonStyles.Wide
export let disabled = false
export let href: string = '#'
export let click: () => void = () => {
goto(href)
}
export let style: ButtonStyles = ButtonStyles.Wide
export let disabled = false
export let href: string = '#'
export let click: () => void = () => {
goto(href)
}
const size = style === ButtonStyles.Micro ? 'sm' : 'lg'
</script>
<button class={style} {disabled} on:click={click}> <slot /></button>
<style type="text/scss">
button,
.button {
min-width: 100px;
width: 100px;
white-space: nowrap;
border-radius: 5px;
color: white;
background: rgb(10, 10, 120);
display: inline-block;
margin-left: auto;
margin-right: auto;
padding: 10px;
font-size: 30px;
&:hover {
cursor: pointer;
text-decoration: none;
}
&:disabled {
background: rgb(64, 64, 107);
color: lightgray;
}
&.wide {
width: 100%;
}
&.micro {
width: initial;
padding: 2px;
padding-left: 5px;
padding-right: 5px;
min-width: initial;
max-width: initial;
font-size: 10px;
}
}
</style>
<Button
class={style}
color={'primary'}
{disabled}
block={style === ButtonStyles.Wide}
{size}
on:click={click}><slot /></Button
>

View File

@ -1,5 +1,5 @@
<script lang="ts">
import { onMount, tick, createEventDispatcher } from 'svelte'
import { createEventDispatcher, tick } from 'svelte'
const dispatch = createEventDispatcher()

View File

@ -0,0 +1,32 @@
<script lang="ts">
import { Card, CardBody, CardHeader, CardText, CardTitle } from 'sveltestrap'
import Check from './Icons/Check.svelte'
export let title: string
</script>
<main>
<Card class="">
<CardHeader>
<CardTitle><Check /> {title}</CardTitle>
</CardHeader>
<CardBody style={'height: 220px'}>
<CardText>
<div class="body">
<slot />
</div>
</CardText>
</CardBody>
</Card>
</main>
<style lang="scss">
main {
width: 300px;
margin: 5px;
display: inline-block;
}
.body {
text-align: left;
}
</style>

View File

@ -0,0 +1,8 @@
<div class="gap" />
<style lang="scss">
.gap {
height: 10px;
width: 100%;
}
</style>

View File

@ -0,0 +1,5 @@
<script lang="ts">
import { Icon } from 'sveltestrap'
</script>
<Icon name="check" />

View File

@ -0,0 +1,54 @@
<script lang="ts">
import { redirect } from '$util/redirect'
import { isLoggedIn, logOut, user } from '@pockethost/common/src/pocketbase'
import { Collapse, Nav, Navbar, NavbarBrand, NavbarToggler, NavItem, NavLink } from 'sveltestrap'
import logo from '../assets/logo-square.png'
import NavbarBrandImage from './NavbarBrandImage.svelte'
import Title from './Title/Title.svelte'
import { TitleSize } from './Title/types'
let isOpen = false
function handleUpdate(event: CustomEvent<boolean>) {
isOpen = event.detail.valueOf()
}
const handleLogout = () => {
logOut()
redirect(`/`)
}
</script>
<Navbar color="light" light expand="md">
<NavbarBrand href="/">
<NavbarBrandImage {logo} />
<Title size={TitleSize.Nav} first="pocket" second="host" third=".io" /></NavbarBrand
>
<NavbarToggler on:click={() => (isOpen = !isOpen)} />
<Collapse {isOpen} navbar expand="md" on:update={handleUpdate}>
<Nav class="ms-auto" navbar>
{#if isLoggedIn()}
<NavItem>
<div class="navbar-text">Welcome back, {user()?.email}</div>
</NavItem>
<NavItem>
<NavLink href="/dashboard">Dashboard</NavLink>
</NavItem>
<NavItem>
<NavLink on:click={handleLogout}>Logout</NavLink>
</NavItem>
{/if}
{#if !isLoggedIn()}
<NavItem>
<NavLink href="/signup">Sign up</NavLink>
</NavItem>
<NavItem>
<NavLink href="/login">Log in</NavLink>
</NavItem>
{/if}
</Nav>
</Collapse>
</Navbar>
<style lang="scss">
</style>

View File

@ -0,0 +1,12 @@
<script lang="ts">
export let logo: string
</script>
<img class="logo d-inline-block align-text-top" src={logo} />
<style lang="scss">
img.logo {
height: 30px;
margin-right: 10px;
}
</style>

View File

@ -1,31 +1,14 @@
<script lang="ts">
import { isLoggedIn, logOut, user } from '@pockethost/common/src/pocketbase'
import Button from './Button/Button.svelte'
import { ButtonStyles } from './Button/types'
import { browser } from '$app/environment'
import { redirect } from '$util/redirect'
import { isLoggedIn } from '@pockethost/common/src/pocketbase'
if (typeof window !== 'undefined' && !isLoggedIn()) {
window.location.href = '/signup'
}
const handleLogout = () => {
logOut()
window.location.href = '/'
if (browser && !isLoggedIn()) {
redirect(`/signup`)
}
</script>
<div class="logbar">
{user()?.email}
<Button style={ButtonStyles.Micro} click={handleLogout}>Log Out</Button>
<div>
<a href="/dashboard">dashboard</a>
</div>
</div>
<slot />
<style lang="scss">
.logbar {
position: absolute;
right: 0px;
top: 0px;
}
</style>

View File

@ -1,10 +1,13 @@
<script lang="ts">
import { TitleSize } from './types'
export let first = 'Pocket'
export let second = 'Host'
export let third = ''
export let size: TitleSize = TitleSize.Normal
</script>
<h1>{first}<span id="host">{second}</span>{third}</h1>
<h1 class={size}>{first}<span id="host">{second}</span>{third}</h1>
<style type="text/scss">
h1 {
@ -18,5 +21,10 @@
#host {
color: blue;
}
&.nav {
font-size: 15px;
font-weight: 400;
display: inline-block;
}
}
</style>

View File

@ -0,0 +1,4 @@
export enum TitleSize {
Nav = 'nav',
Normal = 'normal'
}

View File

@ -0,0 +1,8 @@
<script>
import Navbar from '$components/Navbar.svelte'
import { Styles } from 'sveltestrap'
</script>
<Styles />
<Navbar />
<slot />

View File

@ -1,21 +1,78 @@
<script lang="ts">
import Title from '../components/Title.svelte'
import Button from '../components/Button/Button.svelte'
import AuthCheck from '../components/AuthCheck.svelte'
import Caption from '../components/Caption/Caption.svelte'
import { CaptionSize } from '../components/Caption/types'
import Button from '$components/Button/Button.svelte'
import { ButtonStyles } from '$components/Button/types'
import Caption from '$components/Caption/Caption.svelte'
import { CaptionSize } from '$components/Caption/types'
import Feature from '$components/Feature.svelte'
import Gap from '$components/Gap.svelte'
</script>
<AuthCheck>
<Title third=".io" />
<main>
<Caption size={CaptionSize.Hero}>
The zero config, zero setup <a href="https://pocketbase.io">PocketBase</a>
backend for your next app.
</Caption>
<Button href="/signup">Get Started</Button>
</main>
</AuthCheck>
<main>
<Caption size={CaptionSize.Hero}>Firebase and Supabase...<br />ljbf</Caption>
<div style="max-width: 400px; margin-left: auto; margin-right: auto">
<Button href="/signup" style={ButtonStyles.Wide}>Get Started Free</Button>
</div>
<Gap />
<div>
<Feature title={`Up in 30 seconds`}>
<p>
A backend for your next app is as fast as signing up. No provisioning servers, no Docker
fiddling, just B(ad)aaS productivity.
</p>
<ul>
<li>Sign up</li>
<li>Pick a unique project name</li>
<li>Connect with our JS client</li>
</ul>
</Feature>
<Feature title={'Zero Config'}
>With PocketHost, batteries are included. You get a database, outgoing email, SSL,
authentication, cloud functions, and high concurrency all in one stop.</Feature
>
<Feature title={'Database'}>
Your PocketHost instance is powered by its own internal SQLite instance. SQLite is <a
href="https://pocketbase.io/faq/"
target="_blank">more performant than mySQL or Postgres</a
>
and is
<a href="https://www.sqlite.org/whentouse.html" target="_blank"
>perfect for powering your next app</a
>.
</Feature>
<Feature title={'Auth'}
>Email and oAuth authentication options work out of the box. Send transactional email to your
users from our verified domain and your custom address, <code>yoursubdomin@pockethost.io</code
>.</Feature
>
<Feature title={'Storage'}
>PocketHost securely stores your files on Amazon S3, or you can use your own key to manage
your own storage.</Feature
>
<Feature title={'Room to Grow'}
>PocketHost is perfect for hobbist, low, and medium volume sites and apps.
<p>
PocketHost, and the underlying PocketBase, can scale to well over 10,000 simultaneous
connections.
</p></Feature
>
<Feature title={`Self-host`}>
When you're ready to take your project in-house, we have you covered. You can export your
entire PocketHost environment along with a Dockerfile to run it.
</Feature>
<Feature title={'Open Source Stack'}
>PocketHost is powered by Svelte, Vite, Typescript, PocketBase, and SQLite. Because the entire
stack is open source, you'll never be locked into the whims of a vendor.</Feature
>
<Feature title={'Coming Soon'}>
<ul>
<li>JS/TS cloud functions</li>
<li>Deploy to Fly.io</li>
<li>Lightstream</li>
</ul>
</Feature>
</div>
</main>
<style type="text/scss">
main {

View File

@ -1,67 +1,66 @@
<script lang="ts">
import { page } from '$app/stores'
import { identity } from 'ts-brand'
import Caption from '../../../../components/Caption/Caption.svelte'
import CodeSample from '../../../../components/CodeSample.svelte'
import Protected from '../../../../components/Protected.svelte'
import Title from '../../../../components/Title.svelte'
import { isBrowser } from '@pockethost/common/src/isBrowser'
import { assertExists } from '@pockethost/common/src/assert'
import { getInstanceById, watchInstanceById } from '@pockethost/common/src/pocketbase'
import {
InstanceStatuses,
type InstanceId,
type Instance_Out
} from '@pockethost/common/src/schema'
import { onDestroy, onMount } from 'svelte'
import type { Unsubscriber } from 'svelte/store'
import ProvisioningStatus from '../../../../components/ProvisioningStatus/ProvisioningStatus.svelte'
import { ProvisioningSize } from '../../../../components/ProvisioningStatus/types'
import { page } from '$app/stores'
import Caption from '$components/Caption/Caption.svelte'
import CodeSample from '$components/CodeSample.svelte'
import Protected from '$components/Protected.svelte'
import ProvisioningStatus from '$components/ProvisioningStatus/ProvisioningStatus.svelte'
import { ProvisioningSize } from '$components/ProvisioningStatus/types'
import Title from '$components/Title/Title.svelte'
import { assertExists } from '@pockethost/common/src/assert'
import { watchInstanceById } from '@pockethost/common/src/pocketbase'
import {
InstanceStatuses,
type InstanceId,
type Instance_Out
} from '@pockethost/common/src/schema'
import { onDestroy, onMount } from 'svelte'
import type { Unsubscriber } from 'svelte/store'
import { identity } from 'ts-brand'
const { instanceId } = $page.params
const { instanceId } = $page.params
let instance: Instance_Out | undefined
let instance: Instance_Out | undefined
let url: string
let code: string = ''
let unsub: Unsubscriber = () => {}
onMount(() => {
unsub = watchInstanceById(identity<InstanceId>(instanceId), (r) => {
console.log(`got a record`, r)
instance = r
assertExists(instance, `Expected instance here`)
const { subdomain } = instance
url = `https://${subdomain}.pockethost.io`
code = `const url = '${url}'\nconst client = new PocketBase(url)`
})
})
onDestroy(() => unsub())
let url: string
let code: string = ''
let unsub: Unsubscriber = () => {}
onMount(() => {
unsub = watchInstanceById(identity<InstanceId>(instanceId), (r) => {
console.log(`got a record`, r)
instance = r
assertExists(instance, `Expected instance here`)
const { subdomain } = instance
url = `https://${subdomain}.pockethost.io`
code = `const url = '${url}'\nconst client = new PocketBase(url)`
})
})
onDestroy(() => unsub())
</script>
<Protected>
<Title />
{#if instance}
{#if instance.status === InstanceStatuses.Started}
<Caption>Your PocketHost instance is now live.</Caption>
<div>
Admin URL: <a href={`${url}/_`} target="_blank">{`${url}/_`}</a>
</div>
<div>
JavaScript:
<CodeSample {code} />
</div>
{/if}
{#if instance.status !== InstanceStatuses.Started}
<Caption>Please stand by, your instance is starting now...</Caption>
<div class="provisioning">
<ProvisioningStatus status={instance.status} size={ProvisioningSize.Hero} />
</div>
{/if}
{/if}
<Title />
{#if instance}
{#if instance.status === InstanceStatuses.Started}
<Caption>Your PocketHost instance is now live.</Caption>
<div>
Admin URL: <a href={`${url}/_`} target="_blank">{`${url}/_`}</a>
</div>
<div>
JavaScript:
<CodeSample {code} />
</div>
{/if}
{#if instance.status !== InstanceStatuses.Started}
<Caption>Please stand by, your instance is starting now...</Caption>
<div class="provisioning">
<ProvisioningStatus status={instance.status} size={ProvisioningSize.Hero} />
</div>
{/if}
{/if}
</Protected>
<style lang="scss">
.provisioning {
text-align: center;
}
.provisioning {
text-align: center;
}
</style>

View File

@ -1,95 +1,96 @@
<script lang="ts">
import { faRefresh } from '@fortawesome/free-solid-svg-icons'
import PocketBase from 'pocketbase'
import { generateSlug } from 'random-word-slugs'
import Fa from 'svelte-fa/src/fa.svelte'
import Button from '../../../components/Button/Button.svelte'
import { ButtonStyles } from '../../../components/Button/types'
import Error from '../../../components/Error/Error.svelte'
import { parseError } from '../../../components/Error/parseError'
import Protected from '../../../components/Protected.svelte'
import Title from '../../../components/Title.svelte'
import { createInstance, user } from '@pockethost/common/src/pocketbase'
import { redirect } from '../../../util/redirect'
import { identity } from 'ts-brand'
import { assertExists } from '@pockethost/common/src/assert'
import type { Subdomain, UserId } from '@pockethost/common/src/schema'
import { browser } from '$app/environment'
import Button from '$components/Button/Button.svelte'
import { ButtonStyles } from '$components/Button/types'
import Error from '$components/Error/Error.svelte'
import { parseError } from '$components/Error/parseError'
import Protected from '$components/Protected.svelte'
import Title from '$components/Title/Title.svelte'
import { redirect } from '$util/redirect'
import { faRefresh } from '@fortawesome/free-solid-svg-icons'
import { assertExists } from '@pockethost/common/src/assert'
import { createInstance, user } from '@pockethost/common/src/pocketbase'
import type { Subdomain, UserId } from '@pockethost/common/src/schema'
import PocketBase from 'pocketbase'
import { generateSlug } from 'random-word-slugs'
import Fa from 'svelte-fa'
import { identity } from 'ts-brand'
const client = new PocketBase('https://db.pockethost.io')
if (!client.authStore.isValid && typeof window !== 'undefined') {
window.location.href = '/signup'
}
let instanceName = generateSlug(2)
const client = new PocketBase('https://db.pockethost.io')
if (browser && !client.authStore.isValid) {
redirect('/signup')
}
let instanceName = generateSlug(2)
let errorMessage = ''
let code = ''
$: {
code = `const url = 'https://${instanceName}.pockethost.io'\nconst client = new PocketBase(url)`
}
let errorMessage = ''
let code = ''
$: {
code = `const url = 'https://${instanceName}.pockethost.io'\nconst client = new PocketBase(url)`
}
const handleCreate = () => {
console.log(`creating `, instanceName)
const { id } = user() || {}
assertExists<UserId>(id, `Expected uid here`)
createInstance({
subdomain: identity<Subdomain>(instanceName),
uid: id
})
.then((rec) => {
console.log(`Record`, rec)
redirect(`/app/instances/${rec.id}`)
})
.catch((e) => {
errorMessage = parseError(e)
console.error(errorMessage, e)
})
}
const handleCreate = () => {
console.log(`creating `, instanceName)
const { id } = user() || {}
assertExists<UserId>(id, `Expected uid here`)
createInstance({
subdomain: identity<Subdomain>(instanceName),
uid: id
})
.then((rec) => {
console.log(`Record`, rec)
redirect(`/app/instances/${rec.id}`)
})
.catch((e) => {
errorMessage = parseError(e)
console.error(errorMessage, e)
})
}
</script>
<Protected>
<Title />
<main>
<h2>New App</h2>
<div class="caption">Choose a name for your PocketBase app.</div>
<div class="subdomain">
<label for="instanceName">Instance Name</label>
<Button click={() => (instanceName = generateSlug(2))} style={ButtonStyles.Micro}>
<Fa icon={faRefresh} /></Button
>
<Title />
<main>
<h2>New App</h2>
<div class="caption">Choose a name for your PocketBase app.</div>
<div class="subdomain">
<label for="instanceName">Instance Name</label>
<Button click={() => (instanceName = generateSlug(2))} style={ButtonStyles.Micro}>
<Fa icon={faRefresh} /></Button
>
<input
class="subdomain"
name="instanceName"
type="text"
bind:value={instanceName}
/>.pockethost.io
</div>
<Error>{errorMessage}</Error>
<Button click={handleCreate}>Create</Button>
</main>
<input
class="subdomain"
name="instanceName"
type="text"
bind:value={instanceName}
/>.pockethost.io
</div>
<Error>{errorMessage}</Error>
<Button click={handleCreate}>Create</Button>
</main>
</Protected>
<style type="text/scss">
main {
padding: 1em;
margin-left: auto;
margin-right: auto;
label {
display: block;
font-weight: bold;
width: 200px;
}
.caption {
font-size: 15px;
margin-top: 20px;
margin-bottom: 20px;
}
.subdomain {
input {
text-align: right;
max-width: 200px;
}
white-space: nowrap;
}
}
main {
padding: 1em;
margin-left: auto;
margin-right: auto;
label {
display: block;
font-weight: bold;
width: 200px;
}
.caption {
font-size: 15px;
margin-top: 20px;
margin-bottom: 20px;
}
.subdomain {
input {
text-align: right;
max-width: 200px;
}
white-space: nowrap;
}
}
</style>

View File

@ -1,57 +1,57 @@
<script lang="ts">
import { getAllInstancesById } from '@pockethost/common/src/pocketbase'
import { InstanceStatuses, type Instance_Out_ByIdCollection } from '@pockethost/common/src/schema'
import { values } from '@s-libs/micro-dash'
import Button from '../../components/Button/Button.svelte'
import { ButtonStyles } from '../../components/Button/types'
import Protected from '../../components/Protected.svelte'
import Title from '../../components/Title.svelte'
import ProvisioningStatus from '../../components/ProvisioningStatus/ProvisioningStatus.svelte'
import Button from '$components/Button/Button.svelte'
import { ButtonStyles } from '$components/Button/types'
import Protected from '$components/Protected.svelte'
import ProvisioningStatus from '$components/ProvisioningStatus/ProvisioningStatus.svelte'
import Title from '$components/Title/Title.svelte'
import { getAllInstancesById } from '@pockethost/common/src/pocketbase'
import { InstanceStatuses, type Instance_Out_ByIdCollection } from '@pockethost/common/src/schema'
import { values } from '@s-libs/micro-dash'
let apps: Instance_Out_ByIdCollection = {}
getAllInstancesById()
.then((instances) => {
apps = instances
})
.catch((e) => {
console.error(`Failed to fetch instances`)
})
let apps: Instance_Out_ByIdCollection = {}
getAllInstancesById()
.then((instances) => {
apps = instances
})
.catch((e) => {
console.error(`Failed to fetch instances`)
})
</script>
<Protected>
<Title />
<main>
<h2>Dashboard</h2>
<h4>Apps</h4>
{#each values(apps) as app}
<div>
<ProvisioningStatus status={app.status} />
{app.subdomain}.pockethost.io
<Title />
<main>
<h2>Dashboard</h2>
<h4>Apps</h4>
{#each values(apps) as app}
<div>
<ProvisioningStatus status={app.status} />
{app.subdomain}.pockethost.io
<Button style={ButtonStyles.Micro} href={`/app/instances/${app.id}`}>Details</Button>
<Button
disabled={app.status !== InstanceStatuses.Started}
style={ButtonStyles.Micro}
click={() => {
window.open(`https://${app.subdomain}.pockethost.io/_`)
}}>Admin</Button
>
</div>
{/each}
<Button href="/app/new">+</Button>
</main>
<Button style={ButtonStyles.Micro} href={`/app/instances/${app.id}`}>Details</Button>
<Button
disabled={app.status !== InstanceStatuses.Started}
style={ButtonStyles.Micro}
click={() => {
window.open(`https://${app.subdomain}.pockethost.io/_`)
}}>Admin</Button
>
</div>
{/each}
<Button href="/app/new">+</Button>
</main>
</Protected>
<style type="text/scss">
main {
padding: 1em;
margin-left: auto;
margin-right: auto;
main {
padding: 1em;
margin-left: auto;
margin-right: auto;
.caption {
font-size: 30px;
margin-top: 20px;
margin-bottom: 20px;
}
}
.caption {
font-size: 30px;
margin-top: 20px;
margin-bottom: 20px;
}
}
</style>

View File

@ -1,65 +1,64 @@
<script lang="ts">
import { ClientResponseError } from 'pocketbase'
import AuthCheck from '../../components/AuthCheck.svelte'
import Button from '../../components/Button/Button.svelte'
import Title from '../../components/Title.svelte'
import { authViaEmail, createUser } from '@pockethost/common/src/pocketbase'
import Button from '$components/Button/Button.svelte'
import Title from '$components/Title/Title.svelte'
import { redirect } from '$util/redirect'
import { authViaEmail } from '@pockethost/common/src/pocketbase'
let email = ''
let password = ''
let loginError = ''
let email = ''
let password = ''
let loginError = ''
const handleLogin = () => {
loginError = ''
authViaEmail(email, password)
.then((user) => {
console.log(user)
window.location.href = '/dashboard'
})
.catch((e) => {
loginError = e.message
})
}
const handleLogin = () => {
loginError = ''
authViaEmail(email, password)
.then((user) => {
console.log(user)
redirect('/dashboard')
})
.catch((e) => {
loginError = e.message
})
}
</script>
<Title first="Log" second="In" />
<main>
<error>{loginError}</error>
<div>
<label for="email">Email</label>
<input name="email" type="email" bind:value={email} />
</div>
<div>
<label for="password">Password</label>
<input name="password" type="password" bind:value={password} />
</div>
<div>
Need to <a href="/signup">create an account</a>?
</div>
<Button click={handleLogin} disabled={email.length === 0 || password.length === 0}>Log In</Button>
<error>{loginError}</error>
<div>
<label for="email">Email</label>
<input name="email" type="email" bind:value={email} />
</div>
<div>
<label for="password">Password</label>
<input name="password" type="password" bind:value={password} />
</div>
<div>
Need to <a href="/signup">create an account</a>?
</div>
<Button click={handleLogin} disabled={email.length === 0 || password.length === 0}>Log In</Button>
</main>
<style type="text/scss">
error {
color: red;
display: block;
}
error {
color: red;
display: block;
}
label {
display: block;
font-weight: bold;
width: 200px;
}
main {
padding: 1em;
margin-left: auto;
margin-right: auto;
}
label {
display: block;
font-weight: bold;
width: 200px;
}
main {
padding: 1em;
margin-left: auto;
margin-right: auto;
}
.caption {
font-size: 30px;
margin-top: 20px;
margin-bottom: 20px;
}
.caption {
font-size: 30px;
margin-top: 20px;
margin-bottom: 20px;
}
</style>

View File

@ -1,84 +1,85 @@
<script lang="ts">
import { authViaEmail, createUser } from '@pockethost/common/src/pocketbase';
import Button from '../../components/Button/Button.svelte';
import { parseError } from '../../components/Error/parseError';
import Title from '../../components/Title.svelte';
import Button from '$components/Button/Button.svelte'
import { parseError } from '$components/Error/parseError'
import Title from '$components/Title/Title.svelte'
import { redirect } from '$util/redirect'
import { authViaEmail, createUser } from '@pockethost/common/src/pocketbase'
let email = '';
let errorMessage = '';
let password = '';
let passwordError = '';
let email = ''
let errorMessage = ''
let password = ''
let passwordError = ''
// client.users
// .authViaEmail('ben@benallfree.com', 'Dhjb2X6C1y0W')
// .then((u) => {
// console.log(`user logged in`, u)
// window.location.href = '/dashboard'
// })
// .catch((e) => console.error(`user login error`, e))
// client.users
// .authViaEmail('ben@benallfree.com', 'Dhjb2X6C1y0W')
// .then((u) => {
// console.log(`user logged in`, u)
// window.location.href = '/dashboard'
// })
// .catch((e) => console.error(`user login error`, e))
const handleSignup = () => {
errorMessage = '';
passwordError = '';
createUser(email, password)
.then((user) => {
console.log({ user });
const handleSignup = () => {
errorMessage = ''
passwordError = ''
createUser(email, password)
.then((user) => {
console.log({ user })
authViaEmail(email, password)
.then((u) => {
console.log(`user logged in`, u);
window.location.href = '/dashboard';
})
.catch((e) => console.error(`user login error`, e));
})
.catch((e) => {
errorMessage = parseError(e);
console.error(errorMessage, e);
});
};
authViaEmail(email, password)
.then((u) => {
console.log(`user logged in`, u)
redirect('/dashboard')
})
.catch((e) => console.error(`user login error`, e))
})
.catch((e) => {
errorMessage = parseError(e)
console.error(errorMessage, e)
})
}
</script>
<Title first="Sign" second="Up" />
<main>
<div>
<label for="email">Email</label>
<input name="email" type="email" bind:value={email} />
<error>{errorMessage}</error>
</div>
<div>
<label for="password">Password</label>
<input name="password" type="password" bind:value={password} />
<error>{passwordError}</error>
</div>
<Button click={handleSignup} disabled={email.length === 0 || password.length === 0}>
Sign Up
</Button>
<div>
Already have an account? <a href="/login">Log in</a>
</div>
<div>
<label for="email">Email</label>
<input name="email" type="email" bind:value={email} />
<error>{errorMessage}</error>
</div>
<div>
<label for="password">Password</label>
<input name="password" type="password" bind:value={password} />
<error>{passwordError}</error>
</div>
<Button click={handleSignup} disabled={email.length === 0 || password.length === 0}>
Sign Up
</Button>
<div>
Already have an account? <a href="/login">Log in</a>
</div>
</main>
<style type="text/scss">
error {
color: red;
display: block;
}
error {
color: red;
display: block;
}
label {
display: block;
font-weight: bold;
width: 200px;
}
main {
padding: 1em;
margin-left: auto;
margin-right: auto;
}
label {
display: block;
font-weight: bold;
width: 200px;
}
main {
padding: 1em;
margin-left: auto;
margin-right: auto;
}
.caption {
font-size: 30px;
margin-top: 20px;
margin-bottom: 20px;
}
.caption {
font-size: 30px;
margin-top: 20px;
margin-bottom: 20px;
}
</style>

View File

@ -800,6 +800,11 @@
resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1"
integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==
"@popperjs/core@^2.9.2":
version "2.11.6"
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.6.tgz#cee20bd55e68a1720bdab363ecf0c821ded4cd45"
integrity sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==
"@rollup/pluginutils@^4.2.1":
version "4.2.1"
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-4.2.1.tgz#e6c6c3aba0744edce3fb2074922d3776c0af2a6d"
@ -2586,6 +2591,13 @@ svelte@^3.44.0:
resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.50.1.tgz#b35fbc5e79ddd71e8bb27c3149ee6ff903841239"
integrity sha512-bS4odcsdj5D5jEg6riZuMg5NKelzPtmsCbD9RG+8umU03TeNkdWnP6pqbCm0s8UQNBkqk29w/Bdubn3C+HWSwA==
sveltestrap@^5.9.0:
version "5.9.0"
resolved "https://registry.yarnpkg.com/sveltestrap/-/sveltestrap-5.9.0.tgz#69cffd4d1178d69da423b097a34d185294b9e1c0"
integrity sha512-ZSiYKYrKhDMhhbamnAFK3RK/uqUdcLgjae5Fk3GYdv6Ccth0tN2y6vSg+Vp/PBTYc51u08ZwnYvt8SfWSRNCMA==
dependencies:
"@popperjs/core" "^2.9.2"
svgo@^2.4.0:
version "2.8.0"
resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24"