-
Notifications
You must be signed in to change notification settings - Fork 128
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding some install steps to app tutorial, and adding a page to
explain the contacts list components and store
- Loading branch information
1 parent
7792448
commit a132303
Showing
7 changed files
with
425 additions
and
27 deletions.
There are no files selected for viewing
12 changes: 6 additions & 6 deletions
12
docs/building-apps/example-application-tutorial/_category_.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
{ | ||
"position": 55, | ||
"label": "Example Application Tutorial", | ||
"link": { | ||
"type": "generated-index" | ||
} | ||
} | ||
"position": 55, | ||
"label": "Example Application Tutorial", | ||
"link": { | ||
"type": "generated-index" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
155 changes: 155 additions & 0 deletions
155
docs/building-apps/example-application-tutorial/contacts-list.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
--- | ||
title: Contacts List | ||
sidebar_position: 15 | ||
--- | ||
|
||
A central feature for _BasicPay_ is a list of contacts that contains a user's name, and a Stellar address associated with it. While this particular function doesn't do a _tremendous_ amount of Stellar-related functionality, it makes sense for it to be the first thing we discuss. Understanding this simple component will set a good foundation for you to understand some of the more advanced components later on. | ||
|
||
## Creating a `localStorage` store | ||
|
||
As with the rest of our user-data, the contacts list will live in the browser's `localStorage`. We are using the [`svelt-local-storage-store` package] to facilitate this. We create a Svelte `store` to hold the data, and add a few custom functions to manage the list: `empty`, `remove`, `add`, `favorite`, and `lookup`. | ||
|
||
:::note | ||
|
||
This tutorial code is simplified for display here. The code is fully typed, documented, and commented in the [source code repository]. | ||
|
||
::: | ||
|
||
```js file="/src/lib/stores/contactsStore.js" | ||
import { v4 as uuidv4 } from 'uuid' | ||
import { persisted } from 'svelte-local-storage-store' | ||
import { StrKey } from 'stellar-sdk' | ||
import { error } from '@sveltejs/kit' | ||
import { get } from 'svelte/store' | ||
|
||
// We are wrapping this store in its own function which will allow us to write | ||
// and customize our own store functions to maintain consistent behavior | ||
// wherever the actions need to take place. | ||
function createContactsStore() { | ||
const { subscribe, set, update } = persisted('bpa:contactList', []) | ||
|
||
return { | ||
subscribe, | ||
|
||
// Erases all contact entries from the list and creates a new, empty contact list. | ||
empty: () => set([]), | ||
|
||
// Removes the specified contact entry from the list. | ||
remove: (id) => update((list) => list.filter((contact) => contact.id !== id)), | ||
|
||
// Adds a new contact entry to the list with the provided details. | ||
add: (contact) => | ||
update((list) => { | ||
if (StrKey.isValidEd25519PublicKey(contact.address)) { | ||
return [...list, { ...contact, id: uuidv4() }] | ||
} else { | ||
throw error(400, { message: 'invalid public key' }) | ||
} | ||
}), | ||
|
||
// Toggles the "favorite" field on the specified contact. | ||
favorite: (id) => | ||
update((list) => { | ||
const i = list.findIndex((contact) => contact.id === id) | ||
if (i >= 0) { | ||
list[i].favorite = !list[i].favorite | ||
} | ||
return list | ||
}), | ||
|
||
// Searches the contact list for an entry with the specified address. | ||
lookup: (address) => { | ||
let list = get(contacts) | ||
let i = list.findIndex((contact) => contact.address === address) | ||
if (i >= 0) { | ||
return list[i].name | ||
} else { | ||
return false | ||
} | ||
}, | ||
} | ||
} | ||
|
||
// We export `contacts` as the variable that can be used to interact with the contacts store. | ||
export const contacts = createContactsStore() | ||
``` | ||
|
||
Source: <https://github.com/stellar/basic-payment-app/blob/main/src/lib/stores/contactsStore.js> | ||
|
||
## Accessing the `localStore` data | ||
|
||
The `contacts` store is now exported form this file, and can be accessed and used inside a Svelte page or component. Here is how we've implemented a "favorite contacts" component for displaying on the main BasicPay dashboard. | ||
|
||
:::note | ||
|
||
In our `*.svelte` component files, we will not dive too deeply into the HTML markup outside of the `<script>` tags. The Svelte syntax is primarily used for iterating and is quite undertandable. | ||
|
||
::: | ||
|
||
```svelte file="/src/routes/dashboard/components/FavoriteContacts.svelte" | ||
<script> | ||
// We import the `contacts` store into our Svelte component | ||
// highlight-next-line | ||
import { contacts } from '$lib/stores/contactsStore' | ||
import TruncatedKey from '$lib/components/TruncatedKey.svelte' | ||
|
||
// `$:` makes a Svelte variable reactive, so it will be re-computed any time | ||
// the `$contacts` store is modified. We access a Svelte store by adding `$` | ||
// to the beginning of the variable name. | ||
// highlight-next-line | ||
$: favoriteContacts = $contacts?.filter((contact) => contact.favorite) | ||
</script> | ||
|
||
<h3>Favorite Contacts</h3> | ||
<table class="table w-full"> | ||
<thead> | ||
<tr> | ||
<th>Favorite</th> | ||
<th>Name</th> | ||
<th>Address</th> | ||
</tr> | ||
</thead> | ||
{#if favoriteContacts} | ||
<tbody> | ||
{#each favoriteContacts as contact (contact.id)} | ||
<tr> | ||
<th> | ||
<input | ||
type="checkbox" | ||
class="checkbox-accent checkbox checkbox-sm" | ||
checked={contact.favorite} | ||
on:click={() => contacts.favorite(contact.id)} | ||
/> | ||
</th> | ||
<td> | ||
<div class="flex items-center space-x-3"> | ||
<div class="avatar"> | ||
<div class="not-prose w-10 rounded-full"> | ||
<img | ||
src="https://id.lobstr.co/{contact.address}.png" | ||
alt="Avatar Tailwind CSS Component" | ||
/> | ||
</div> | ||
</div> | ||
<div> | ||
<div class="font-bold">{contact.name}</div> | ||
</div> | ||
</div> | ||
</td> | ||
<td> | ||
<TruncatedKey keyText={contact.address} lookupName={false} /> | ||
</td> | ||
<th> | ||
<button class="btn-ghost btn-xs btn">Stellar.Expert</button> | ||
</th> | ||
</tr> | ||
{/each} | ||
</tbody> | ||
{/if} | ||
</table> | ||
``` | ||
Source: <https://github.com/stellar/basic-payment-app/blob/main/src/routes/dashboard/components/FavoriteContacts.svelte> | ||
[`svelt-local-storage-store` package]: <https://github.com/joshnuss/svelte-local-storage-store> | ||
[source code repository]: <https://github.com/stellar/basic-payment-app> |
Oops, something went wrong.