Skip to content
Merged
2 changes: 1 addition & 1 deletion docs/tools/dapps/lsp-factoryjs/_category_.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
label: '🏭 lsp-factory.js (deprecated)'
collapsed: true
position: 6
position: 7
3 changes: 3 additions & 0 deletions docs/tools/dapps/up-modal/_category_.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
label: '🪟 up-modal'
collapsed: true
position: 6
88 changes: 88 additions & 0 deletions docs/tools/dapps/up-modal/api-reference.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
---
sidebar_position: 2
title: 'API Reference'
---

# API Reference

## `setupLuksoConnector`

Returns `Promise<LuksoConnector>`. Call once at app initialization. Example with custom options:

```typescript
const connector = await setupLuksoConnector({
theme: 'dark',
walletConnect: {
projectId: 'YOUR_REOWN_PROJECT_ID', // get yours at https://cloud.reown.com
},
chains: {
enableTestnet: true,
},
connectors: {
eoa: false,
},
onConnect: (event) => console.log('Connected:', event.detail),
onError: (event) => console.error('Error:', event.detail),
onClose: () => console.log('Modal closed'),
});
```

### Config Options

| Option | Type | Default | Description |
| ------------------------- | ----------------------------- | ------------- | --------------------------------------- |
| `theme` | `'light' \| 'dark' \| 'auto'` | `'light'` | Modal theme |
| `onConnect` | `(e: CustomEvent) => void` | — | Called on successful connection |
| `onError` | `(e: CustomEvent) => void` | — | Called on connection error |
| `onClose` | `() => void` | — | Called when modal is closed |
| `walletConnect.enabled` | `boolean` | `true` | Enable WalletConnect |
| `walletConnect.projectId` | `string` | LUKSO default | WalletConnect project ID |
| `chains.defaultChainId` | `number` | `42` | Default chain (LUKSO mainnet) |
| `chains.enableTestnet` | `boolean` | `false` | Also enable LUKSO testnet (4201) |
| `storage.key` | `string` | `'up-wagmi'` | localStorage key prefix for wagmi state |
| `connectors.upMobile` | `boolean` | `true` | Show UP Mobile connector button |
| `connectors.upExtension` | `boolean` | `true` | Show UP Extension connector button |
| `connectors.eoa` | `boolean` | `true` | Show EOA wallets divider and button |
| `wagmiConfig` | `Config` (from `@wagmi/core`) | auto-created | Pass your own wagmi config |

## `LuksoConnector` Methods

| Method | Description |
| ------------------- | ------------------------------------------------------------------------------------ |
| `showSignInModal()` | Opens the sign-in modal (creates `<connect-modal>` in `document.body` on first call) |
| `showSignUpModal()` | Opens the sign-up modal for creating a new Universal Profile |
| `closeModal()` | Closes the modal |
| `setTheme(theme)` | Updates the theme (`'light' \| 'dark' \| 'auto'`) — works while modal is open |
| `destroyModal()` | Closes the modal and removes the element from the DOM |
| `wagmiConfig` | The underlying wagmi `Config` instance for advanced use |

## Advanced

### Using Your Own Wagmi Config

```typescript
import { setupLuksoConnector } from '@lukso/up-modal';
import { myWagmiConfig } from './wagmi';

const connector = await setupLuksoConnector({
wagmiConfig: myWagmiConfig,
});
```

### Watching Connection State

```typescript
import { watchConnection, getConnection } from '@wagmi/core';

const { wagmiConfig } = connector;

// One-time read
const connection = getConnection(wagmiConfig);

// Subscribe to changes
const stopWatching = watchConnection(wagmiConfig, {
onChange: (connection) => {
console.log(connection.address, connection.chainId);
},
});
```
39 changes: 39 additions & 0 deletions docs/tools/dapps/up-modal/customization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
sidebar_position: 3
title: 'Customization'
---

# Customization

The modal supports visual customization via CSS variables. Set them on `:root` or any ancestor of the `<connect-modal>` element.

## CSS Variables

| Variable | Description | Default |
| ---------------------------- | -------------------------- | --------------------------------------------- |
| `--up-modal-font-family` | Modal font family | `Inter, ui-sans-serif, system-ui, sans-serif` |
| `--up-modal-font-color` | Modal text color (light) | `#243542` |
| `--up-modal-font-dark-color` | Modal text color (dark) | `#f5f8fa` |
| `--up-modal-btn-color` | Button background (light) | `#ffffff` |
| `--up-modal-btn-dark-color` | Button background (dark) | `#243542` |
| `--up-modal-btn-text` | Button text & icon (light) | `#243542` |
| `--up-modal-btn-dark-text` | Button text & icon (dark) | `#ffffff` |
| `--up-modal-btn-radius` | Button border radius | `12px` (large) / `10px` (medium) |
| `--up-modal-border-radius` | Modal border radius | `12px` |
| `--up-modal-bg` | Modal background (light) | `#f8fafb` |
| `--up-modal-dark-bg` | Modal background (dark) | `#121b21` |

## Example: Custom Brand Colors

```html
<style>
:root {
--up-modal-font-family: 'Roboto', sans-serif;
--up-modal-font-color: #1e3a5f;
--up-modal-btn-color: #4285f4;
--up-modal-btn-text: #ffffff;
--up-modal-bg: #eff6ff;
--up-modal-border-radius: 20px;
}
</style>
```
261 changes: 261 additions & 0 deletions docs/tools/dapps/up-modal/getting-started.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
---
sidebar_position: 1
title: 'Getting Started'
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Getting Started

The [`@lukso/up-modal`](https://www.npmjs.com/package/@lukso/up-modal) package provides a connect modal for LUKSO Universal Profiles. It offers a responsive connection dialog with support for desktop and mobile, automatically detecting UP Mobile (via WalletConnect), UP Browser Extension (via EIP-6963), and other EOA wallets. Modal works with apps that use [Wagmi](https://wagmi.sh), a library to interact Ethereum. Wagmi handles the underlying connection management, so you can use its APIs alongside the modal.

<div style={{textAlign: 'center', display: 'flex', justifyContent: 'center', gap: '16px', flexWrap: 'wrap'}}>
<img src="/img/tools/up-modal/modal-light.png" alt="Light theme" width="320" />
<img src="/img/tools/up-modal/modal-dark.png" alt="Dark theme" width="320" />
</div>

## What gets auto-detected

Modal automatically configures:

| App | How |
| ---------------- | ------------------------------------------------------- |
| **UP Mobile** | WalletConnect (deep link on mobile, QR code on desktop) |
| **UP Extension** | Browser extension, detected via EIP-6963 |
| **EOA wallets** | Other EIP-6963 wallets (MetaMask, Coinbase, etc.) |

## Installation

```bash
# pnpm
pnpm add @lukso/up-modal

# npm
npm install @lukso/up-modal

# yarn
yarn add @lukso/up-modal
```

Also install the required peer dependencies:

```bash
npm install @wagmi/core viem
```

## Minimal Setup

### Initialize modal

```typescript
import { setupLuksoConnector } from '@lukso/up-modal';

const connector = await setupLuksoConnector({
walletConnect: {
projectId: 'YOUR_REOWN_PROJECT_ID', // get yours at https://cloud.reown.com
},
});
```

### Open the Sign In modal

```typescript
connector.showSignInModal();
```

### Open the Sign Up modal

```typescript
connector.showSignUpModal();
```

<img src="/img/tools/up-modal/sign-up.png" alt="Sign Up" width="400" />

## Framework Integrations

<Tabs groupId="framework">
<TabItem value="vue" label="Vue 3">

Full working [example](https://github.com/universal-everything/up-modal-vue-example).

**`connector.ts`** (singleton, initialize once):

```typescript
import { setupLuksoConnector, type LuksoConnector } from '@lukso/up-modal';

export const connectorPromise: Promise<LuksoConnector> = setupLuksoConnector({
theme: 'light',
});
```

**`App.vue`**:

```html
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
import { getConnection, disconnect } from '@wagmi/core';
import { connectorPromise } from './connector';

const address = ref<string | null>(null);
const connector = ref<Awaited<typeof connectorPromise> | null>(null);
const ready = ref(false);
let unwatch: (() => void) | null = null;

onMounted(async () => {
connector.value = await connectorPromise;
const { wagmiConfig } = connector.value;

function syncAddress() {
const conn = getConnection(wagmiConfig);
address.value = conn?.isConnected ? (conn.address ?? null) : null;
}

syncAddress();
ready.value = true;
unwatch = wagmiConfig.subscribe((s) => s.status, syncAddress);
});

onUnmounted(() => unwatch?.());

function openModal() {
connector.value?.showSignInModal();
}

async function handleDisconnect() {
await disconnect(connector.value!.wagmiConfig);
address.value = null;
}
</script>

<template>
<div v-if="ready && address">
<p>Connected: {{ address }}</p>
<button @click="handleDisconnect">Disconnect</button>
</div>
<button v-else-if="ready" @click="openModal">Connect</button>
</template>
```

</TabItem>

<TabItem value="nuxt" label="Nuxt">

**Plugin** (`plugins/lukso.client.ts`):

```typescript
import { setupLuksoConnector } from '@lukso/up-modal';
import type { LuksoConnector } from '@lukso/up-modal';

let connector: LuksoConnector | null = null;

export default defineNuxtPlugin(async () => {
if (process.server) return;

connector = await setupLuksoConnector({
theme: 'light',
onConnect: (event) => console.log('Connected:', event.detail),
});
});

export { connector };
```

**Component**:

```html
<template>
<button @click="connector?.showSignInModal()">Connect Wallet</button>
</template>

<script setup lang="ts">
import { connector } from '~/plugins/lukso.client';
</script>
```

</TabItem>

<TabItem value="react" label="React">

Full working [example](https://github.com/universal-everything/up-modal-react-example).

```tsx
import { setupLuksoConnector } from '@lukso/up-modal';
import type { LuksoConnector } from '@lukso/up-modal';
import { useEffect, useState } from 'react';

export function ConnectButton() {
const [connector, setConnector] = useState<LuksoConnector | null>(null);

useEffect(() => {
setupLuksoConnector({
theme: 'light',
onConnect: (event) => console.log('Connected:', event.detail),
}).then(setConnector);
}, []);

return (
<button disabled={!connector} onClick={() => connector?.showSignInModal()}>
Connect Wallet
</button>
);
}
```

**Watching connection state** (requires `@wagmi/core`):

```typescript
import { watchConnection } from '@wagmi/core';

const stopWatching = watchConnection(connector.wagmiConfig, {
onChange: (connection) => {
console.log('Address:', connection.address);
},
});
```

</TabItem>

<TabItem value="svelte" label="Svelte">

**Initialization** (`src/lib/connector.svelte.ts`):

```typescript
import { setupLuksoConnector } from '@lukso/up-modal';
import type { LuksoConnector } from '@lukso/up-modal';

export const connector: { current: LuksoConnector | null } = $state({
current: null,
});

export async function initConnector() {
connector.current = await setupLuksoConnector({
theme: 'light',
onConnect: (e) => console.log('Connected:', e.detail),
});
}
```

**Component** (`ConnectButton.svelte`):

```svelte
<script lang="ts">
import { connector, initConnector } from '$lib/connector.svelte'

$effect(() => {
initConnector();
});
</script>

<button onclick={() => connector.current?.showSignInModal()}>
Connect Wallet
</button>
```

</TabItem>
</Tabs>

## Resources

- [GitHub repo](https://github.com/lukso-network/service-auth-simple/tree/main/packages/up-modal)
- [NPM package](https://www.npmjs.com/package/@lukso/up-modal)
Loading
Loading